From 675af8692d711198ca327e147dbbdaa03316e771 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:14:09 -0700 Subject: [PATCH 001/115] WIP switching from OpenImageIO to libpng. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Common/Code/Source/FrameCaptureSystemComponent.cpp | 8 -------- .../Code/Source/Platform/Windows/platform_windows.cmake | 7 +------ .../Utils/Code/Platform/Windows/platform_windows.cmake | 1 + .../Platform/Android/BuiltInPackages_android.cmake | 1 + cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake | 1 + cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake | 1 + .../Platform/Windows/BuiltInPackages_windows.cmake | 1 + cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake | 1 + 8 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index 6fbdf5b3f0..e3d3186f73 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -32,17 +32,12 @@ #include #include -#if defined(OPEN_IMAGE_IO_ENABLED) -#include -#endif - namespace AZ { namespace Render { AZ_ENUM_DEFINE_REFLECT_UTILITIES(FrameCaptureResult); -#if defined(OPEN_IMAGE_IO_ENABLED) AZ_CVAR(unsigned int, r_pngCompressionLevel, 3, // A compression level of 3 seems like the best default in terms of file size and saving speeds @@ -112,7 +107,6 @@ namespace AZ return FrameCaptureOutputResult{FrameCaptureResult::InternalError, "Unable to save frame capture output to " + outputFilePath}; } -#endif FrameCaptureOutputResult DdsFrameCaptureOutput( const AZStd::string& outputFilePath, const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult) @@ -471,7 +465,6 @@ namespace AZ m_result = ddsFrameCapture.m_result; m_latestCaptureInfo = ddsFrameCapture.m_errorMessage.value_or(""); } -#if defined(OPEN_IMAGE_IO_ENABLED) else if (extension == "png") { if (readbackResult.m_imageDescriptor.m_format == RHI::Format::R8G8B8A8_UNORM || @@ -492,7 +485,6 @@ namespace AZ m_result = FrameCaptureResult::UnsupportedFormat; } } -#endif else { m_latestCaptureInfo = AZStd::string::format("Only supports saving image to ppm or dds files"); diff --git a/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake b/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake index b74260a5de..2932e891ce 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake +++ b/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake @@ -10,10 +10,5 @@ set(LY_BUILD_DEPENDENCIES PRIVATE 3rdParty::OpenImageIO 3rdParty::ilmbase -) - -# [GFX-TODO] Add macro defintion in OpenImageIO 3rd party find cmake file -set(LY_COMPILE_DEFINITIONS - PRIVATE - OPEN_IMAGE_IO_ENABLED + 3rdParty::libpng ) diff --git a/Gems/Atom/Utils/Code/Platform/Windows/platform_windows.cmake b/Gems/Atom/Utils/Code/Platform/Windows/platform_windows.cmake index c1d40c6ad8..ead5aa05de 100644 --- a/Gems/Atom/Utils/Code/Platform/Windows/platform_windows.cmake +++ b/Gems/Atom/Utils/Code/Platform/Windows/platform_windows.cmake @@ -9,4 +9,5 @@ set(LY_BUILD_DEPENDENCIES PRIVATE 3rdParty::OpenImageIO + 3rdParty::libpng ) diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index a65e8b45e4..435678f29e 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -25,6 +25,7 @@ ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-android TARGETS Phy ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-android TARGETS mikkelsen PACKAGE_HASH 075e8e4940884971063b5a9963014e2e517246fa269c07c7dc55b8cf2cd99705) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-android TARGETS googletest PACKAGE_HASH 95671be75287a61c9533452835c3647e9c1b30f81b34b43bcb0ec1997cc23894) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-android TARGETS GoogleBenchmark PACKAGE_HASH 20b46e572211a69d7d94ddad1c89ec37bb958711d6ad4025368ac89ea83078fb) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 0000000000000000000000000000000000000000000000000000000000000000) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-android TARGETS libsamplerate PACKAGE_HASH bf13662afe65d02bcfa16258a4caa9b875534978227d6f9f36c9cfa92b3fb12b) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-android TARGETS OpenSSL PACKAGE_HASH 4036d4019d722f0e1b7a1621bf60b5a17ca6a65c9c78fd8701cee1131eec8480) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev1-android TARGETS zlib PACKAGE_HASH 832b163cae0cccbe4fddc5988f5725fac56ef7dba5bfe95bf8c71281fba2e12c) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 7df364121b..56f00d351e 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -39,6 +39,7 @@ ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-linux ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-linux TARGETS GoogleBenchmark PACKAGE_HASH 4038878f337fc7e0274f0230f71851b385b2e0327c495fc3dd3d1c18a807928d) ly_associate_package(PACKAGE_NAME unwind-1.2.1-linux TARGETS unwind PACKAGE_HASH 3453265fb056e25432f611a61546a25f60388e315515ad39007b5925dd054a77) ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-linux TARGETS Qt PACKAGE_HASH 76b395897b941a173002845c7219a5f8a799e44b269ffefe8091acc048130f28) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 0000000000000000000000000000000000000000000000000000000000000000) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-linux TARGETS libsamplerate PACKAGE_HASH 41643c31bc6b7d037f895f89d8d8d6369e906b92eff42b0fe05ee6a100f06261) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-linux TARGETS OpenSSL PACKAGE_HASH b779426d1e9c5ddf71160d5ae2e639c3b956e0fb5e9fcaf9ce97c4526024e3bc) ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-linux TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 88c4a359325d749bc34090b9ac466424847f3b71ba0de15045cf355c17c07099) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index 353956a495..c0dbd13257 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -41,5 +41,6 @@ ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-mac ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-mac TARGETS GoogleBenchmark PACKAGE_HASH ad25de0146769c91e179953d845de2bec8ed4a691f973f47e3eb37639381f665) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-mac TARGETS OpenSSL PACKAGE_HASH 28adc1c0616ac0482b2a9d7b4a3a3635a1020e87b163f8aba687c501cf35f96c) ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-mac TARGETS Qt PACKAGE_HASH 9d25918351898b308ded3e9e571fff6f26311b2071aeafd00dd5b249fdf53f7e) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 0000000000000000000000000000000000000000000000000000000000000000) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-mac TARGETS libsamplerate PACKAGE_HASH b912af40c0ac197af9c43d85004395ba92a6a859a24b7eacd920fed5854a97fe) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev1-mac TARGETS zlib PACKAGE_HASH 7fd8a77b3598423d9d6be5f8c60d52aecf346ab4224f563a5282db283aa0da02) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 2aded62bcd..fea4017db7 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -45,6 +45,7 @@ ly_associate_package(PACKAGE_NAME d3dx12-headers-rev1-windows ly_associate_package(PACKAGE_NAME pyside2-qt-5.15.1-rev2-windows TARGETS pyside2 PACKAGE_HASH c90f3efcc7c10e79b22a33467855ad861f9dbd2e909df27a5cba9db9fa3edd0f) ly_associate_package(PACKAGE_NAME openimageio-2.1.16.0-rev2-windows TARGETS OpenImageIO PACKAGE_HASH 85a2a6cf35cbc4c967c56ca8074babf0955c5b490c90c6e6fd23c78db99fc282) ly_associate_package(PACKAGE_NAME qt-5.15.2-rev4-windows TARGETS Qt PACKAGE_HASH a4634caaf48192cad5c5f408504746e53d338856148285057274f6a0ccdc071d) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-windows TARGETS libpng PACKAGE_HASH 3240dbbccd4bf89a6676243c0e0301dafe6e7c8965d952098c1aa48a7ba60b8a) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-windows TARGETS libsamplerate PACKAGE_HASH dcf3c11a96f212a52e2c9241abde5c364ee90b0f32fe6eeb6dcdca01d491829f) ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev1-windows TARGETS OpenMesh PACKAGE_HASH 1c1df639358526c368e790dfce40c45cbdfcfb1c9a041b9d7054a8949d88ee77) ly_associate_package(PACKAGE_NAME civetweb-1.8-rev1-windows TARGETS civetweb PACKAGE_HASH 36d0e58a59bcdb4dd70493fb1b177aa0354c945b06c30416348fd326cf323dd4) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index c288460dd0..c392f365f0 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -26,6 +26,7 @@ ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-ios TARGETS PhysX ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-ios TARGETS mikkelsen PACKAGE_HASH 976aaa3ccd8582346132a10af253822ccc5d5bcc9ea5ba44d27848f65ee88a8a) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-ios TARGETS googletest PACKAGE_HASH 2f121ad9784c0ab73dfaa58e1fee05440a82a07cc556bec162eeb407688111a7) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-ios TARGETS GoogleBenchmark PACKAGE_HASH c2ffaed2b658892b1bcf81dee4b44cd1cb09fc78d55584ef5cb8ab87f2d8d1ae) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 0000000000000000000000000000000000000000000000000000000000000000) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-ios TARGETS libsamplerate PACKAGE_HASH 7656b961697f490d4f9c35d2e61559f6fc38c32102e542a33c212cd618fc2119) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-ios TARGETS OpenSSL PACKAGE_HASH cd0dfce3086a7172777c63dadbaf0ac3695b676119ecb6d0614b5fb1da03462f) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev1-ios TARGETS zlib PACKAGE_HASH 20bfccf3b98bd9a7d3506cf344ac48135035eb517752bf9bede1e821f163608d) From 7a8eb8eda59e416db634fadcafc79bee080c5d6a Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 8 Sep 2021 12:56:24 -0700 Subject: [PATCH 002/115] Added a new PngImage utility class that wraps libpng. This replaces the use of OpenImageIO in O3DE (although OpenImageIO is still a build dependency for now). Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Source/FrameCaptureSystemComponent.cpp | 30 +- .../Platform/Windows/platform_windows.cmake | 1 - Gems/Atom/Utils/Code/CMakeLists.txt | 1 + .../Utils/Code/Include/Atom/Utils/PngFile.h | 94 ++++++ Gems/Atom/Utils/Code/Source/PngFile.cpp | 295 ++++++++++++++++++ Gems/Atom/Utils/Code/atom_utils_files.cmake | 2 + .../Windows/BuiltInPackages_windows.cmake | 2 +- 7 files changed, 406 insertions(+), 19 deletions(-) create mode 100644 Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h create mode 100644 Gems/Atom/Utils/Code/Source/PngFile.cpp diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index e3d3186f73..6201ff5e56 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -86,26 +87,21 @@ namespace AZ jobCompletion.StartAndWaitForCompletion(); } - using namespace OIIO; - AZStd::unique_ptr out = ImageOutput::create(outputFilePath.c_str()); - if (out) - { - ImageSpec spec( - readbackResult.m_imageDescriptor.m_size.m_width, - readbackResult.m_imageDescriptor.m_size.m_height, - numChannels - ); - spec.attribute("png:compressionLevel", r_pngCompressionLevel); + PngImage image = PngImage::Create(readbackResult.m_imageDescriptor.m_size, readbackResult.m_imageDescriptor.m_format, *buffer); - if (out->open(outputFilePath.c_str(), spec)) - { - out->write_image(TypeDesc::UINT8, buffer->data()); - out->close(); - return FrameCaptureOutputResult{FrameCaptureResult::Success, AZStd::nullopt}; - } + PngImage::SaveSettings saveSettings; + saveSettings.m_compressionLevel = r_pngCompressionLevel; + // We should probably strip alpha to save space, especially for automated test screenshots. Alpha is left in to maintain + // prior behavior, changing this is out of scope for the current task. Note, it would have bit of a cascade effect where + // AtomSampleViewer's ScriptReporter assumes an RGBA image. + saveSettings.m_stripAlpha = false; + + if(image && image.Save(outputFilePath.c_str(), saveSettings)) + { + return FrameCaptureOutputResult{FrameCaptureResult::Success, AZStd::nullopt}; } - return FrameCaptureOutputResult{FrameCaptureResult::InternalError, "Unable to save frame capture output to " + outputFilePath}; + return FrameCaptureOutputResult{FrameCaptureResult::InternalError, "Unable to save frame capture output to '" + outputFilePath + "'"}; } FrameCaptureOutputResult DdsFrameCaptureOutput( diff --git a/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake b/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake index 2932e891ce..8357d45a33 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake +++ b/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake @@ -8,7 +8,6 @@ set(LY_BUILD_DEPENDENCIES PRIVATE - 3rdParty::OpenImageIO 3rdParty::ilmbase 3rdParty::libpng ) diff --git a/Gems/Atom/Utils/Code/CMakeLists.txt b/Gems/Atom/Utils/Code/CMakeLists.txt index 63a2e029f7..1beefc01f6 100644 --- a/Gems/Atom/Utils/Code/CMakeLists.txt +++ b/Gems/Atom/Utils/Code/CMakeLists.txt @@ -24,6 +24,7 @@ ly_add_target( Gem::Atom_RHI.Public PUBLIC Gem::Atom_RHI.Reflect + 3rdParty::libpng ) ################################################################################ diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h new file mode 100644 index 0000000000..1f168df02a --- /dev/null +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h @@ -0,0 +1,94 @@ +/* + * 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 AZ +{ + //! This is a light wrapper class for libpng, to load and save .png files. + //! Functionality is limited, feel free to add more features as needed. + class PngImage + { + public: + using ErrorHandler = AZStd::function; + + struct LoadSettings + { + ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered + bool m_stripAlpha = false; //!< the alpha channel will be skipped, loading an RGBA image as RGB + }; + + struct SaveSettings + { + ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered + bool m_stripAlpha = false; //!< the alpha channel will be skipped, saving an RGBA buffer as RGB + int m_compressionLevel = 6; //!< this is the zlib compression level. See png_set_compression_level in png.h + }; + + // To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel. + enum class Format + { + Unknown, + RGB, + RGBA + }; + + //! @return the loaded PngImage or an invalid PngImage if there was an error. + static PngImage Load(const char* path, LoadSettings loadSettings = {}); + + //! Create a PngImage from an RHI data buffer. + //! @param size the dimensions of the image (m_depth is not used, assumed to be 1) + //! @param format indicates the pixel format represented by @data. Only a limited set of formats are supported, see implementation. + //! @param data the buffer of image data. The size of the buffer must match the @size and @format parameters. + //! @return the created PngImage or an invalid PngImage if there was an error. + static PngImage Create(const RHI::Size& size, RHI::Format format, AZStd::array_view data); + static PngImage Create(const RHI::Size& size, RHI::Format format, AZStd::vector&& data); + + PngImage() = default; + AZ_DEFAULT_MOVE(PngImage) + + //! @return true if the save operation was successful + bool Save(const char* path, SaveSettings saveSettings = {}); + + bool IsValid() const; + operator bool() const { return IsValid(); } + + uint32_t GetWidth() const { return m_width; } + uint32_t GetHeight() const { return m_height; } + + Format GetBufferFormat() const { return m_bufferFormat; } + const AZStd::vector& GetBuffer() const { return m_buffer; } + + //! Returns a r-value reference that can be moved. This will invalidate the PngImage. + AZStd::vector&& TakeBuffer(); + + private: + AZ_DEFAULT_COPY(PngImage) + + static const int HeaderSize = 8; + + static void DefaultErrorHandler(const char* message); + + // See png_get_IHDR in http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf... + uint32_t m_width = 0; + uint32_t m_height = 0; + int32_t m_bitDepth = 0; + int32_t m_colorType = 0; + + Format m_bufferFormat = Format::Unknown; + AZStd::vector m_buffer; + }; +} // namespace AZ diff --git a/Gems/Atom/Utils/Code/Source/PngFile.cpp b/Gems/Atom/Utils/Code/Source/PngFile.cpp new file mode 100644 index 0000000000..273ea88358 --- /dev/null +++ b/Gems/Atom/Utils/Code/Source/PngFile.cpp @@ -0,0 +1,295 @@ +/* + * 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 +{ + namespace + { + void PngImage_user_error_fn(png_structp png_ptr, png_const_charp error_msg) + { + PngImage::ErrorHandler* errorHandler = reinterpret_cast(png_get_error_ptr(png_ptr)); + (*errorHandler)(error_msg); + } + + void PngImage_user_warning_fn(png_structp /*png_ptr*/, png_const_charp warning_msg) + { + AZ_Warning("PngImage", false, "%s", warning_msg); + } + } + + PngImage PngImage::Create(const RHI::Size& size, RHI::Format format, AZStd::array_view data) + { + return Create(size, format, AZStd::vector{data.begin(), data.end()}); + } + + PngImage PngImage::Create(const RHI::Size& size, RHI::Format format, AZStd::vector&& data) + { + PngImage image; + + if (RHI::Format::R8G8B8A8_UNORM == format) + { + if (size.m_width * size.m_height * 4 == data.size()) + { + image.m_width = size.m_width; + image.m_height = size.m_height; + image.m_bitDepth = 8; + image.m_colorType = PNG_COLOR_TYPE_RGB_ALPHA; + image.m_bufferFormat = PngImage::Format::RGBA; + image.m_buffer = data; + } + else + { + AZ_Assert(false, "Invalid arguments. Buffer size does not match the image dimensions."); + } + } + + return image; + } + + PngImage PngImage::Load(const char* path, LoadSettings loadSettings) + { + if (!loadSettings.m_errorHandler) + { + loadSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not load file '%s'. %s", path, message).c_str()); }; + } + + // For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 3 + + FILE* fp = NULL; + if (fopen_s(&fp, path, "rb") || !fp) + { + loadSettings.m_errorHandler("Failed to open file."); + return {}; + } + + png_byte header[HeaderSize] = {}; + + if (fread(header, 1, HeaderSize, fp) != HeaderSize) + { + fclose(fp); + loadSettings.m_errorHandler("Invalid header."); + return {}; + } + + bool isPng = !png_sig_cmp(header, 0, HeaderSize); + if (!isPng) + { + fclose(fp); + loadSettings.m_errorHandler("Invalid header."); + return {}; + } + + png_voidp user_error_ptr = &loadSettings.m_errorHandler; + png_error_ptr user_error_fn = PngImage_user_error_fn; + png_error_ptr user_warning_fn = PngImage_user_warning_fn; + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn); + if (!png_ptr) + { + fclose(fp); + loadSettings.m_errorHandler("png_create_read_struct failed."); + return {}; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + fclose(fp); + loadSettings.m_errorHandler("png_create_info_struct failed."); + return {}; + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fp); + loadSettings.m_errorHandler("png_create_info_struct failed."); + return {}; + } + +#pragma warning(push) +#pragma warning(disable: 4611) // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160 + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(fp); + // We don't report an error message here because the user_error_fn should have done that already. + return {}; + } +#pragma warning(pop) + + png_init_io(png_ptr, fp); + + png_set_sig_bytes(png_ptr, HeaderSize); + + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, 0); + + // To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel + int png_transforms = PNG_TRANSFORM_PACKING | // Expand 1, 2 and 4-bit samples to bytes + PNG_TRANSFORM_STRIP_16 | // Reduce 16 bit samples to 8 bits + PNG_TRANSFORM_GRAY_TO_RGB; + + if (loadSettings.m_stripAlpha) + { + png_transforms |= PNG_TRANSFORM_STRIP_ALPHA; + } + + png_read_png(png_ptr, info_ptr, png_transforms, NULL); + + // Note that libpng will allocate row_pointers for us. If we want to manage the memory ourselves, we need to call png_set_rows. + // In that case we would have to use the low level interface: png_read_info, png_read_image, and png_read_end. + png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr); + + PngImage pngImage; + + png_get_IHDR(png_ptr, info_ptr, &pngImage.m_width, &pngImage.m_height, &pngImage.m_bitDepth, &pngImage.m_colorType, NULL, NULL, NULL); + + uint32_t bytesPerPixel = 0; + + switch (pngImage.m_colorType) + { + case PNG_COLOR_TYPE_RGB: + pngImage.m_bufferFormat = PngImage::Format::RGB; + bytesPerPixel = 3; + break; + case PNG_COLOR_TYPE_RGBA: + pngImage.m_bufferFormat = PngImage::Format::RGBA; + bytesPerPixel = 4; + break; + default: + AZ_Assert(false, "The png transforms should have ensured a pixel format of RGB or RGBA, 8 bits per channel"); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fp); + loadSettings.m_errorHandler("Unsupported pixel format."); + return {}; + } + + // In the future we could use the low-level interface to avoid copying the image (and provide progress callbacks) + pngImage.m_buffer.set_capacity(pngImage.m_width * pngImage.m_height * bytesPerPixel); + for (uint32_t rowIndex = 0; rowIndex < pngImage.m_height; ++rowIndex) + { + png_bytep row = row_pointers[rowIndex]; + pngImage.m_buffer.insert(pngImage.m_buffer.end(), row, row + (pngImage.m_width * bytesPerPixel)); + } + + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(fp); + return pngImage; + } + + bool PngImage::Save(const char* path, SaveSettings saveSettings) + { + if (!saveSettings.m_errorHandler) + { + saveSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not save file '%s'. %s", path, message).c_str()); }; + } + + if (!IsValid()) + { + saveSettings.m_errorHandler("This PngImage is invalid."); + return false; + } + + // For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 4 + + FILE* fp = NULL; + if (fopen_s(&fp, path, "wb") || !fp) + { + saveSettings.m_errorHandler("Failed to open file."); + return false; + } + + png_voidp user_error_ptr = &saveSettings.m_errorHandler; + png_error_ptr user_error_fn = PngImage_user_error_fn; + png_error_ptr user_warning_fn = PngImage_user_warning_fn; + + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn); + if (!png_ptr) + { + fclose(fp); + saveSettings.m_errorHandler("png_create_write_struct failed."); + return false; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + fclose(fp); + saveSettings.m_errorHandler("png_destroy_write_struct failed."); + return false; + } + +#pragma warning(push) +#pragma warning(disable: 4611) // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160 + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + // We don't report an error message here because the user_error_fn should have done that already. + return false; + } +#pragma warning(pop) + + png_init_io(png_ptr, fp); + + png_set_IHDR(png_ptr, info_ptr, m_width, m_height, m_bitDepth, m_colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + png_set_compression_level(png_ptr, saveSettings.m_compressionLevel); + + const uint32_t bytesPerPixel = (m_bufferFormat == PngImage::Format::RGB) ? 3 : 4; + + AZStd::vector rows; + rows.reserve(m_height); + for (uint32_t i = 0; i < m_height; ++i) + { + rows.push_back(m_buffer.begin() + m_width * bytesPerPixel * i); + } + + png_set_rows(png_ptr, info_ptr, rows.begin()); + + int transforms = PNG_TRANSFORM_IDENTITY; + if (saveSettings.m_stripAlpha && m_bufferFormat == PngImage::Format::RGBA) + { + transforms |= PNG_TRANSFORM_STRIP_FILLER_AFTER; + } + + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(fp); + + return true; + } + + void PngImage::DefaultErrorHandler(const char* message) + { + AZ_Error("PngImage", false, "%s", message); + } + + bool PngImage::IsValid() const + { + return + !m_buffer.empty() && + m_width > 0 && + m_height > 0 && + m_bitDepth > 0; + } + + AZStd::vector&& PngImage::TakeBuffer() + { + return AZStd::move(m_buffer); + } + +}// namespace AZ diff --git a/Gems/Atom/Utils/Code/atom_utils_files.cmake b/Gems/Atom/Utils/Code/atom_utils_files.cmake index 06b78a49c4..71b4c8879c 100644 --- a/Gems/Atom/Utils/Code/atom_utils_files.cmake +++ b/Gems/Atom/Utils/Code/atom_utils_files.cmake @@ -21,6 +21,7 @@ set(FILES Include/Atom/Utils/ImGuiFrameVisualizer.inl Include/Atom/Utils/ImGuiTransientAttachmentProfiler.h Include/Atom/Utils/ImGuiTransientAttachmentProfiler.inl + Include/Atom/Utils/PngFile.h Include/Atom/Utils/PpmFile.h Include/Atom/Utils/StableDynamicArray.h Include/Atom/Utils/StableDynamicArray.inl @@ -29,6 +30,7 @@ set(FILES Include/Atom/Utils/AssetCollectionAsyncLoader.h Source/DdsFile.cpp Source/ImageComparison.cpp + Source/PngFile.cpp Source/PpmFile.cpp Source/Utils.cpp Source/AssetCollectionAsyncLoader.cpp diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index fea4017db7..9538f8816a 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -45,7 +45,7 @@ ly_associate_package(PACKAGE_NAME d3dx12-headers-rev1-windows ly_associate_package(PACKAGE_NAME pyside2-qt-5.15.1-rev2-windows TARGETS pyside2 PACKAGE_HASH c90f3efcc7c10e79b22a33467855ad861f9dbd2e909df27a5cba9db9fa3edd0f) ly_associate_package(PACKAGE_NAME openimageio-2.1.16.0-rev2-windows TARGETS OpenImageIO PACKAGE_HASH 85a2a6cf35cbc4c967c56ca8074babf0955c5b490c90c6e6fd23c78db99fc282) ly_associate_package(PACKAGE_NAME qt-5.15.2-rev4-windows TARGETS Qt PACKAGE_HASH a4634caaf48192cad5c5f408504746e53d338856148285057274f6a0ccdc071d) -ly_associate_package(PACKAGE_NAME libpng-1.6.37-windows TARGETS libpng PACKAGE_HASH 3240dbbccd4bf89a6676243c0e0301dafe6e7c8965d952098c1aa48a7ba60b8a) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-windows TARGETS libpng PACKAGE_HASH 011079ecbc09c22852eecd860c70dd89f8c2f923c09be87fec4e18ce1e55d4e7) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-windows TARGETS libsamplerate PACKAGE_HASH dcf3c11a96f212a52e2c9241abde5c364ee90b0f32fe6eeb6dcdca01d491829f) ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev1-windows TARGETS OpenMesh PACKAGE_HASH 1c1df639358526c368e790dfce40c45cbdfcfb1c9a041b9d7054a8949d88ee77) ly_associate_package(PACKAGE_NAME civetweb-1.8-rev1-windows TARGETS civetweb PACKAGE_HASH 36d0e58a59bcdb4dd70493fb1b177aa0354c945b06c30416348fd326cf323dd4) From a9c6909a29070b3f26d58a281b8d815e9a4612cb Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 8 Sep 2021 13:20:54 -0700 Subject: [PATCH 003/115] Renamed PngImage to PngFile and put it in a Utils namespace to match the other file utilities. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Source/FrameCaptureSystemComponent.cpp | 4 +- .../Utils/Code/Include/Atom/Utils/PngFile.h | 143 +++--- Gems/Atom/Utils/Code/Source/PngFile.cpp | 469 +++++++++--------- 3 files changed, 311 insertions(+), 305 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index 6201ff5e56..62113d3827 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -87,9 +87,9 @@ namespace AZ jobCompletion.StartAndWaitForCompletion(); } - PngImage image = PngImage::Create(readbackResult.m_imageDescriptor.m_size, readbackResult.m_imageDescriptor.m_format, *buffer); + Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, readbackResult.m_imageDescriptor.m_format, *buffer); - PngImage::SaveSettings saveSettings; + Utils::PngFile::SaveSettings saveSettings; saveSettings.m_compressionLevel = r_pngCompressionLevel; // We should probably strip alpha to save space, especially for automated test screenshots. Alpha is left in to maintain // prior behavior, changing this is out of scope for the current task. Note, it would have bit of a cascade effect where diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h index 1f168df02a..5a12001122 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h @@ -18,77 +18,80 @@ namespace AZ { - //! This is a light wrapper class for libpng, to load and save .png files. - //! Functionality is limited, feel free to add more features as needed. - class PngImage + namespace Utils { - public: - using ErrorHandler = AZStd::function; - - struct LoadSettings + //! This is a light wrapper class for libpng, to load and save .png files. + //! Functionality is limited, feel free to add more features as needed. + class PngFile { - ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered - bool m_stripAlpha = false; //!< the alpha channel will be skipped, loading an RGBA image as RGB + public: + using ErrorHandler = AZStd::function; + + struct LoadSettings + { + ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered + bool m_stripAlpha = false; //!< the alpha channel will be skipped, loading an RGBA image as RGB + }; + + struct SaveSettings + { + ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered + bool m_stripAlpha = false; //!< the alpha channel will be skipped, saving an RGBA buffer as RGB + int m_compressionLevel = 6; //!< this is the zlib compression level. See png_set_compression_level in png.h + }; + + // To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel. + enum class Format + { + Unknown, + RGB, + RGBA + }; + + //! @return the loaded PngFile or an invalid PngFile if there was an error. + static PngFile Load(const char* path, LoadSettings loadSettings = {}); + + //! Create a PngFile from an RHI data buffer. + //! @param size the dimensions of the image (m_depth is not used, assumed to be 1) + //! @param format indicates the pixel format represented by @data. Only a limited set of formats are supported, see implementation. + //! @param data the buffer of image data. The size of the buffer must match the @size and @format parameters. + //! @return the created PngFile or an invalid PngFile if there was an error. + static PngFile Create(const RHI::Size& size, RHI::Format format, AZStd::array_view data); + static PngFile Create(const RHI::Size& size, RHI::Format format, AZStd::vector&& data); + + PngFile() = default; + AZ_DEFAULT_MOVE(PngFile) + + //! @return true if the save operation was successful + bool Save(const char* path, SaveSettings saveSettings = {}); + + bool IsValid() const; + operator bool() const { return IsValid(); } + + uint32_t GetWidth() const { return m_width; } + uint32_t GetHeight() const { return m_height; } + + Format GetBufferFormat() const { return m_bufferFormat; } + const AZStd::vector& GetBuffer() const { return m_buffer; } + + //! Returns a r-value reference that can be moved. This will invalidate the PngFile. + AZStd::vector&& TakeBuffer(); + + private: + AZ_DEFAULT_COPY(PngFile) + + static const int HeaderSize = 8; + + static void DefaultErrorHandler(const char* message); + + // See png_get_IHDR in http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf... + uint32_t m_width = 0; + uint32_t m_height = 0; + int32_t m_bitDepth = 0; + int32_t m_colorType = 0; + + Format m_bufferFormat = Format::Unknown; + AZStd::vector m_buffer; }; - - struct SaveSettings - { - ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered - bool m_stripAlpha = false; //!< the alpha channel will be skipped, saving an RGBA buffer as RGB - int m_compressionLevel = 6; //!< this is the zlib compression level. See png_set_compression_level in png.h - }; - - // To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel. - enum class Format - { - Unknown, - RGB, - RGBA - }; - - //! @return the loaded PngImage or an invalid PngImage if there was an error. - static PngImage Load(const char* path, LoadSettings loadSettings = {}); - - //! Create a PngImage from an RHI data buffer. - //! @param size the dimensions of the image (m_depth is not used, assumed to be 1) - //! @param format indicates the pixel format represented by @data. Only a limited set of formats are supported, see implementation. - //! @param data the buffer of image data. The size of the buffer must match the @size and @format parameters. - //! @return the created PngImage or an invalid PngImage if there was an error. - static PngImage Create(const RHI::Size& size, RHI::Format format, AZStd::array_view data); - static PngImage Create(const RHI::Size& size, RHI::Format format, AZStd::vector&& data); - - PngImage() = default; - AZ_DEFAULT_MOVE(PngImage) - - //! @return true if the save operation was successful - bool Save(const char* path, SaveSettings saveSettings = {}); - - bool IsValid() const; - operator bool() const { return IsValid(); } - - uint32_t GetWidth() const { return m_width; } - uint32_t GetHeight() const { return m_height; } - - Format GetBufferFormat() const { return m_bufferFormat; } - const AZStd::vector& GetBuffer() const { return m_buffer; } - - //! Returns a r-value reference that can be moved. This will invalidate the PngImage. - AZStd::vector&& TakeBuffer(); - - private: - AZ_DEFAULT_COPY(PngImage) - - static const int HeaderSize = 8; - - static void DefaultErrorHandler(const char* message); - - // See png_get_IHDR in http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf... - uint32_t m_width = 0; - uint32_t m_height = 0; - int32_t m_bitDepth = 0; - int32_t m_colorType = 0; - - Format m_bufferFormat = Format::Unknown; - AZStd::vector m_buffer; - }; + } } // namespace AZ diff --git a/Gems/Atom/Utils/Code/Source/PngFile.cpp b/Gems/Atom/Utils/Code/Source/PngFile.cpp index 273ea88358..5a3fdf7fdb 100644 --- a/Gems/Atom/Utils/Code/Source/PngFile.cpp +++ b/Gems/Atom/Utils/Code/Source/PngFile.cpp @@ -11,285 +11,288 @@ namespace AZ { - namespace + namespace Utils { - void PngImage_user_error_fn(png_structp png_ptr, png_const_charp error_msg) + namespace { - PngImage::ErrorHandler* errorHandler = reinterpret_cast(png_get_error_ptr(png_ptr)); - (*errorHandler)(error_msg); - } - - void PngImage_user_warning_fn(png_structp /*png_ptr*/, png_const_charp warning_msg) - { - AZ_Warning("PngImage", false, "%s", warning_msg); - } - } - - PngImage PngImage::Create(const RHI::Size& size, RHI::Format format, AZStd::array_view data) - { - return Create(size, format, AZStd::vector{data.begin(), data.end()}); - } - - PngImage PngImage::Create(const RHI::Size& size, RHI::Format format, AZStd::vector&& data) - { - PngImage image; - - if (RHI::Format::R8G8B8A8_UNORM == format) - { - if (size.m_width * size.m_height * 4 == data.size()) + void PngImage_user_error_fn(png_structp png_ptr, png_const_charp error_msg) { - image.m_width = size.m_width; - image.m_height = size.m_height; - image.m_bitDepth = 8; - image.m_colorType = PNG_COLOR_TYPE_RGB_ALPHA; - image.m_bufferFormat = PngImage::Format::RGBA; - image.m_buffer = data; + PngFile::ErrorHandler* errorHandler = reinterpret_cast(png_get_error_ptr(png_ptr)); + (*errorHandler)(error_msg); } - else + + void PngImage_user_warning_fn(png_structp /*png_ptr*/, png_const_charp warning_msg) { - AZ_Assert(false, "Invalid arguments. Buffer size does not match the image dimensions."); + AZ_Warning("PngFile", false, "%s", warning_msg); } } - return image; - } - - PngImage PngImage::Load(const char* path, LoadSettings loadSettings) - { - if (!loadSettings.m_errorHandler) + PngFile PngFile::Create(const RHI::Size& size, RHI::Format format, AZStd::array_view data) { - loadSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not load file '%s'. %s", path, message).c_str()); }; - } - - // For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 3 - - FILE* fp = NULL; - if (fopen_s(&fp, path, "rb") || !fp) - { - loadSettings.m_errorHandler("Failed to open file."); - return {}; + return Create(size, format, AZStd::vector{data.begin(), data.end()}); } - png_byte header[HeaderSize] = {}; - - if (fread(header, 1, HeaderSize, fp) != HeaderSize) + PngFile PngFile::Create(const RHI::Size& size, RHI::Format format, AZStd::vector&& data) { - fclose(fp); - loadSettings.m_errorHandler("Invalid header."); - return {}; + PngFile image; + + if (RHI::Format::R8G8B8A8_UNORM == format) + { + if (size.m_width * size.m_height * 4 == data.size()) + { + image.m_width = size.m_width; + image.m_height = size.m_height; + image.m_bitDepth = 8; + image.m_colorType = PNG_COLOR_TYPE_RGB_ALPHA; + image.m_bufferFormat = PngFile::Format::RGBA; + image.m_buffer = data; + } + else + { + AZ_Assert(false, "Invalid arguments. Buffer size does not match the image dimensions."); + } + } + + return image; } - bool isPng = !png_sig_cmp(header, 0, HeaderSize); - if (!isPng) + PngFile PngFile::Load(const char* path, LoadSettings loadSettings) { - fclose(fp); - loadSettings.m_errorHandler("Invalid header."); - return {}; - } + if (!loadSettings.m_errorHandler) + { + loadSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not load file '%s'. %s", path, message).c_str()); }; + } - png_voidp user_error_ptr = &loadSettings.m_errorHandler; - png_error_ptr user_error_fn = PngImage_user_error_fn; - png_error_ptr user_warning_fn = PngImage_user_warning_fn; + // For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 3 - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn); - if (!png_ptr) - { - fclose(fp); - loadSettings.m_errorHandler("png_create_read_struct failed."); - return {}; - } + FILE* fp = NULL; + if (fopen_s(&fp, path, "rb") || !fp) + { + loadSettings.m_errorHandler("Failed to open file."); + return {}; + } - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); - fclose(fp); - loadSettings.m_errorHandler("png_create_info_struct failed."); - return {}; - } + png_byte header[HeaderSize] = {}; - png_infop end_info = png_create_info_struct(png_ptr); - if (!end_info) - { - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - fclose(fp); - loadSettings.m_errorHandler("png_create_info_struct failed."); - return {}; - } + if (fread(header, 1, HeaderSize, fp) != HeaderSize) + { + fclose(fp); + loadSettings.m_errorHandler("Invalid header."); + return {}; + } + + bool isPng = !png_sig_cmp(header, 0, HeaderSize); + if (!isPng) + { + fclose(fp); + loadSettings.m_errorHandler("Invalid header."); + return {}; + } + + png_voidp user_error_ptr = &loadSettings.m_errorHandler; + png_error_ptr user_error_fn = PngImage_user_error_fn; + png_error_ptr user_warning_fn = PngImage_user_warning_fn; + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn); + if (!png_ptr) + { + fclose(fp); + loadSettings.m_errorHandler("png_create_read_struct failed."); + return {}; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + fclose(fp); + loadSettings.m_errorHandler("png_create_info_struct failed."); + return {}; + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fp); + loadSettings.m_errorHandler("png_create_info_struct failed."); + return {}; + } #pragma warning(push) #pragma warning(disable: 4611) // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160 - if (setjmp(png_jmpbuf(png_ptr))) - { + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(fp); + // We don't report an error message here because the user_error_fn should have done that already. + return {}; + } +#pragma warning(pop) + + png_init_io(png_ptr, fp); + + png_set_sig_bytes(png_ptr, HeaderSize); + + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, 0); + + // To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel + int png_transforms = PNG_TRANSFORM_PACKING | // Expand 1, 2 and 4-bit samples to bytes + PNG_TRANSFORM_STRIP_16 | // Reduce 16 bit samples to 8 bits + PNG_TRANSFORM_GRAY_TO_RGB; + + if (loadSettings.m_stripAlpha) + { + png_transforms |= PNG_TRANSFORM_STRIP_ALPHA; + } + + png_read_png(png_ptr, info_ptr, png_transforms, NULL); + + // Note that libpng will allocate row_pointers for us. If we want to manage the memory ourselves, we need to call png_set_rows. + // In that case we would have to use the low level interface: png_read_info, png_read_image, and png_read_end. + png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr); + + PngFile pngFile; + + png_get_IHDR(png_ptr, info_ptr, &pngFile.m_width, &pngFile.m_height, &pngFile.m_bitDepth, &pngFile.m_colorType, NULL, NULL, NULL); + + uint32_t bytesPerPixel = 0; + + switch (pngFile.m_colorType) + { + case PNG_COLOR_TYPE_RGB: + pngFile.m_bufferFormat = PngFile::Format::RGB; + bytesPerPixel = 3; + break; + case PNG_COLOR_TYPE_RGBA: + pngFile.m_bufferFormat = PngFile::Format::RGBA; + bytesPerPixel = 4; + break; + default: + AZ_Assert(false, "The png transforms should have ensured a pixel format of RGB or RGBA, 8 bits per channel"); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fp); + loadSettings.m_errorHandler("Unsupported pixel format."); + return {}; + } + + // In the future we could use the low-level interface to avoid copying the image (and provide progress callbacks) + pngFile.m_buffer.set_capacity(pngFile.m_width * pngFile.m_height * bytesPerPixel); + for (uint32_t rowIndex = 0; rowIndex < pngFile.m_height; ++rowIndex) + { + png_bytep row = row_pointers[rowIndex]; + pngFile.m_buffer.insert(pngFile.m_buffer.end(), row, row + (pngFile.m_width * bytesPerPixel)); + } + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); - // We don't report an error message here because the user_error_fn should have done that already. - return {}; + return pngFile; } -#pragma warning(pop) - png_init_io(png_ptr, fp); - - png_set_sig_bytes(png_ptr, HeaderSize); - - png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, 0); - - // To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel - int png_transforms = PNG_TRANSFORM_PACKING | // Expand 1, 2 and 4-bit samples to bytes - PNG_TRANSFORM_STRIP_16 | // Reduce 16 bit samples to 8 bits - PNG_TRANSFORM_GRAY_TO_RGB; - - if (loadSettings.m_stripAlpha) + bool PngFile::Save(const char* path, SaveSettings saveSettings) { - png_transforms |= PNG_TRANSFORM_STRIP_ALPHA; - } + if (!saveSettings.m_errorHandler) + { + saveSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not save file '%s'. %s", path, message).c_str()); }; + } - png_read_png(png_ptr, info_ptr, png_transforms, NULL); - - // Note that libpng will allocate row_pointers for us. If we want to manage the memory ourselves, we need to call png_set_rows. - // In that case we would have to use the low level interface: png_read_info, png_read_image, and png_read_end. - png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr); + if (!IsValid()) + { + saveSettings.m_errorHandler("This PngFile is invalid."); + return false; + } - PngImage pngImage; + // For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 4 - png_get_IHDR(png_ptr, info_ptr, &pngImage.m_width, &pngImage.m_height, &pngImage.m_bitDepth, &pngImage.m_colorType, NULL, NULL, NULL); - - uint32_t bytesPerPixel = 0; + FILE* fp = NULL; + if (fopen_s(&fp, path, "wb") || !fp) + { + saveSettings.m_errorHandler("Failed to open file."); + return false; + } - switch (pngImage.m_colorType) - { - case PNG_COLOR_TYPE_RGB: - pngImage.m_bufferFormat = PngImage::Format::RGB; - bytesPerPixel = 3; - break; - case PNG_COLOR_TYPE_RGBA: - pngImage.m_bufferFormat = PngImage::Format::RGBA; - bytesPerPixel = 4; - break; - default: - AZ_Assert(false, "The png transforms should have ensured a pixel format of RGB or RGBA, 8 bits per channel"); - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - fclose(fp); - loadSettings.m_errorHandler("Unsupported pixel format."); - return {}; - } + png_voidp user_error_ptr = &saveSettings.m_errorHandler; + png_error_ptr user_error_fn = PngImage_user_error_fn; + png_error_ptr user_warning_fn = PngImage_user_warning_fn; - // In the future we could use the low-level interface to avoid copying the image (and provide progress callbacks) - pngImage.m_buffer.set_capacity(pngImage.m_width * pngImage.m_height * bytesPerPixel); - for (uint32_t rowIndex = 0; rowIndex < pngImage.m_height; ++rowIndex) - { - png_bytep row = row_pointers[rowIndex]; - pngImage.m_buffer.insert(pngImage.m_buffer.end(), row, row + (pngImage.m_width * bytesPerPixel)); - } - - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - fclose(fp); - return pngImage; - } + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn); + if (!png_ptr) + { + fclose(fp); + saveSettings.m_errorHandler("png_create_write_struct failed."); + return false; + } - bool PngImage::Save(const char* path, SaveSettings saveSettings) - { - if (!saveSettings.m_errorHandler) - { - saveSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not save file '%s'. %s", path, message).c_str()); }; - } - - if (!IsValid()) - { - saveSettings.m_errorHandler("This PngImage is invalid."); - return false; - } - - // For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 4 - - FILE* fp = NULL; - if (fopen_s(&fp, path, "wb") || !fp) - { - saveSettings.m_errorHandler("Failed to open file."); - return false; - } - - png_voidp user_error_ptr = &saveSettings.m_errorHandler; - png_error_ptr user_error_fn = PngImage_user_error_fn; - png_error_ptr user_warning_fn = PngImage_user_warning_fn; - - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn); - if (!png_ptr) - { - fclose(fp); - saveSettings.m_errorHandler("png_create_write_struct failed."); - return false; - } - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_write_struct(&png_ptr, (png_infopp)NULL); - fclose(fp); - saveSettings.m_errorHandler("png_destroy_write_struct failed."); - return false; - } + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + fclose(fp); + saveSettings.m_errorHandler("png_destroy_write_struct failed."); + return false; + } #pragma warning(push) #pragma warning(disable: 4611) // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160 - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); - // We don't report an error message here because the user_error_fn should have done that already. - return false; - } + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + // We don't report an error message here because the user_error_fn should have done that already. + return false; + } #pragma warning(pop) - png_init_io(png_ptr, fp); + png_init_io(png_ptr, fp); - png_set_IHDR(png_ptr, info_ptr, m_width, m_height, m_bitDepth, m_colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - png_set_compression_level(png_ptr, saveSettings.m_compressionLevel); + png_set_IHDR(png_ptr, info_ptr, m_width, m_height, m_bitDepth, m_colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - const uint32_t bytesPerPixel = (m_bufferFormat == PngImage::Format::RGB) ? 3 : 4; + png_set_compression_level(png_ptr, saveSettings.m_compressionLevel); - AZStd::vector rows; - rows.reserve(m_height); - for (uint32_t i = 0; i < m_height; ++i) - { - rows.push_back(m_buffer.begin() + m_width * bytesPerPixel * i); + const uint32_t bytesPerPixel = (m_bufferFormat == PngFile::Format::RGB) ? 3 : 4; + + AZStd::vector rows; + rows.reserve(m_height); + for (uint32_t i = 0; i < m_height; ++i) + { + rows.push_back(m_buffer.begin() + m_width * bytesPerPixel * i); + } + + png_set_rows(png_ptr, info_ptr, rows.begin()); + + int transforms = PNG_TRANSFORM_IDENTITY; + if (saveSettings.m_stripAlpha && m_bufferFormat == PngFile::Format::RGBA) + { + transforms |= PNG_TRANSFORM_STRIP_FILLER_AFTER; + } + + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(fp); + + return true; } - png_set_rows(png_ptr, info_ptr, rows.begin()); - - int transforms = PNG_TRANSFORM_IDENTITY; - if (saveSettings.m_stripAlpha && m_bufferFormat == PngImage::Format::RGBA) + void PngFile::DefaultErrorHandler(const char* message) { - transforms |= PNG_TRANSFORM_STRIP_FILLER_AFTER; + AZ_Error("PngFile", false, "%s", message); } - png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + bool PngFile::IsValid() const + { + return + !m_buffer.empty() && + m_width > 0 && + m_height > 0 && + m_bitDepth > 0; + } - png_destroy_write_struct(&png_ptr, &info_ptr); - - fclose(fp); + AZStd::vector&& PngFile::TakeBuffer() + { + return AZStd::move(m_buffer); + } - return true; - } - - void PngImage::DefaultErrorHandler(const char* message) - { - AZ_Error("PngImage", false, "%s", message); - } - - bool PngImage::IsValid() const - { - return - !m_buffer.empty() && - m_width > 0 && - m_height > 0 && - m_bitDepth > 0; - } - - AZStd::vector&& PngImage::TakeBuffer() - { - return AZStd::move(m_buffer); - } - + } // namespace Utils }// namespace AZ From 849a8da4d9fa6ae9aeb85802bae36cb47098b1da Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 8 Sep 2021 23:45:16 -0700 Subject: [PATCH 004/115] Added unit tests for PngFile. Fixed a couple issue like palettized files would not load, and stripping alpha was not affecting the color type reported by libpng. Also cleaned up some error reporting. Added AzFramework to Atom/Utils tests to support PngFile testing. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- Gems/Atom/Utils/Code/CMakeLists.txt | 1 + .../Utils/Code/Include/Atom/Utils/PngFile.h | 7 +- Gems/Atom/Utils/Code/Source/PngFile.cpp | 68 ++-- Gems/Atom/Utils/Code/Tests/PngFileTests.cpp | 327 ++++++++++++++++++ .../Utils/Code/Tests/PngTestImages/.gitignore | 1 + .../Tests/PngTestImages/ColorChart_rgb.png | 3 + .../Tests/PngTestImages/ColorChart_rgba.jpg | 3 + .../Tests/PngTestImages/ColorChart_rgba.png | 3 + .../Tests/PngTestImages/ColorPalette_2bit.png | 3 + .../Code/Tests/PngTestImages/EmptyFile.png | 0 .../PngTestImages/Gradient_rgb_16bpc.png | 3 + .../Tests/PngTestImages/GrayPalette_1bit.png | 3 + .../Utils/Code/atom_utils_tests_files.cmake | 1 + 13 files changed, 398 insertions(+), 25 deletions(-) create mode 100644 Gems/Atom/Utils/Code/Tests/PngFileTests.cpp create mode 100644 Gems/Atom/Utils/Code/Tests/PngTestImages/.gitignore create mode 100644 Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgb.png create mode 100644 Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgba.jpg create mode 100644 Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgba.png create mode 100644 Gems/Atom/Utils/Code/Tests/PngTestImages/ColorPalette_2bit.png create mode 100644 Gems/Atom/Utils/Code/Tests/PngTestImages/EmptyFile.png create mode 100644 Gems/Atom/Utils/Code/Tests/PngTestImages/Gradient_rgb_16bpc.png create mode 100644 Gems/Atom/Utils/Code/Tests/PngTestImages/GrayPalette_1bit.png diff --git a/Gems/Atom/Utils/Code/CMakeLists.txt b/Gems/Atom/Utils/Code/CMakeLists.txt index 1beefc01f6..89bc8dd0a5 100644 --- a/Gems/Atom/Utils/Code/CMakeLists.txt +++ b/Gems/Atom/Utils/Code/CMakeLists.txt @@ -44,6 +44,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) BUILD_DEPENDENCIES PRIVATE AZ::AzTest + AZ::AzFramework Gem::Atom_Utils.Static ) ly_add_googletest( diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h index 5a12001122..7fb2c768ad 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h @@ -55,9 +55,10 @@ namespace AZ //! @param size the dimensions of the image (m_depth is not used, assumed to be 1) //! @param format indicates the pixel format represented by @data. Only a limited set of formats are supported, see implementation. //! @param data the buffer of image data. The size of the buffer must match the @size and @format parameters. + //! @param errorHandler optional callback function describing any errors that are encountered //! @return the created PngFile or an invalid PngFile if there was an error. - static PngFile Create(const RHI::Size& size, RHI::Format format, AZStd::array_view data); - static PngFile Create(const RHI::Size& size, RHI::Format format, AZStd::vector&& data); + static PngFile Create(const RHI::Size& size, RHI::Format format, AZStd::array_view data, ErrorHandler errorHandler = {}); + static PngFile Create(const RHI::Size& size, RHI::Format format, AZStd::vector&& data, ErrorHandler errorHandler = {}); PngFile() = default; AZ_DEFAULT_MOVE(PngFile) @@ -84,11 +85,9 @@ namespace AZ static void DefaultErrorHandler(const char* message); - // See png_get_IHDR in http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf... uint32_t m_width = 0; uint32_t m_height = 0; int32_t m_bitDepth = 0; - int32_t m_colorType = 0; Format m_bufferFormat = Format::Unknown; AZStd::vector m_buffer; diff --git a/Gems/Atom/Utils/Code/Source/PngFile.cpp b/Gems/Atom/Utils/Code/Source/PngFile.cpp index 5a3fdf7fdb..056e199d40 100644 --- a/Gems/Atom/Utils/Code/Source/PngFile.cpp +++ b/Gems/Atom/Utils/Code/Source/PngFile.cpp @@ -27,13 +27,18 @@ namespace AZ } } - PngFile PngFile::Create(const RHI::Size& size, RHI::Format format, AZStd::array_view data) + PngFile PngFile::Create(const RHI::Size& size, RHI::Format format, AZStd::array_view data, ErrorHandler errorHandler) { - return Create(size, format, AZStd::vector{data.begin(), data.end()}); + return Create(size, format, AZStd::vector{data.begin(), data.end()}, errorHandler); } - PngFile PngFile::Create(const RHI::Size& size, RHI::Format format, AZStd::vector&& data) + PngFile PngFile::Create(const RHI::Size& size, RHI::Format format, AZStd::vector&& data, ErrorHandler errorHandler) { + if (!errorHandler) + { + errorHandler = [](const char* message) { DefaultErrorHandler(message); }; + } + PngFile image; if (RHI::Format::R8G8B8A8_UNORM == format) @@ -43,15 +48,18 @@ namespace AZ image.m_width = size.m_width; image.m_height = size.m_height; image.m_bitDepth = 8; - image.m_colorType = PNG_COLOR_TYPE_RGB_ALPHA; image.m_bufferFormat = PngFile::Format::RGBA; - image.m_buffer = data; + image.m_buffer = AZStd::move(data); } else { - AZ_Assert(false, "Invalid arguments. Buffer size does not match the image dimensions."); + errorHandler("Invalid arguments. Buffer size does not match the image dimensions."); } } + else + { + errorHandler(AZStd::string::format("Cannot create PngFile with unsupported format %s", AZ::RHI::ToString(format)).c_str()); + } return image; } @@ -68,7 +76,7 @@ namespace AZ FILE* fp = NULL; if (fopen_s(&fp, path, "rb") || !fp) { - loadSettings.m_errorHandler("Failed to open file."); + loadSettings.m_errorHandler("Cannot open file."); return {}; } @@ -77,7 +85,7 @@ namespace AZ if (fread(header, 1, HeaderSize, fp) != HeaderSize) { fclose(fp); - loadSettings.m_errorHandler("Invalid header."); + loadSettings.m_errorHandler("Invalid png header."); return {}; } @@ -85,7 +93,7 @@ namespace AZ if (!isPng) { fclose(fp); - loadSettings.m_errorHandler("Invalid header."); + loadSettings.m_errorHandler("Invalid png header."); return {}; } @@ -154,11 +162,13 @@ namespace AZ PngFile pngFile; - png_get_IHDR(png_ptr, info_ptr, &pngFile.m_width, &pngFile.m_height, &pngFile.m_bitDepth, &pngFile.m_colorType, NULL, NULL, NULL); + int colorType = 0; + + png_get_IHDR(png_ptr, info_ptr, &pngFile.m_width, &pngFile.m_height, &pngFile.m_bitDepth, &colorType, NULL, NULL, NULL); uint32_t bytesPerPixel = 0; - switch (pngFile.m_colorType) + switch (colorType) { case PNG_COLOR_TYPE_RGB: pngFile.m_bufferFormat = PngFile::Format::RGB; @@ -168,6 +178,12 @@ namespace AZ pngFile.m_bufferFormat = PngFile::Format::RGBA; bytesPerPixel = 4; break; + case PNG_COLOR_TYPE_PALETTE: + // Handles cases where the image uses 1, 2, or 4 bit samples. + // Note bytesPerPixel is 3 because we use PNG_TRANSFORM_PACKING + pngFile.m_bufferFormat = PngFile::Format::RGB; + bytesPerPixel = 3; + break; default: AZ_Assert(false, "The png transforms should have ensured a pixel format of RGB or RGBA, 8 bits per channel"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); @@ -207,7 +223,7 @@ namespace AZ FILE* fp = NULL; if (fopen_s(&fp, path, "wb") || !fp) { - saveSettings.m_errorHandler("Failed to open file."); + saveSettings.m_errorHandler("Cannot open file."); return false; } @@ -245,7 +261,23 @@ namespace AZ png_init_io(png_ptr, fp); - png_set_IHDR(png_ptr, info_ptr, m_width, m_height, m_bitDepth, m_colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + int colorType = 0; + if (saveSettings.m_stripAlpha || m_bufferFormat == PngFile::Format::RGB) + { + colorType = PNG_COLOR_TYPE_RGB; + } + else + { + colorType = PNG_COLOR_TYPE_RGBA; + } + + int transforms = PNG_TRANSFORM_IDENTITY; + if (saveSettings.m_stripAlpha && m_bufferFormat == PngFile::Format::RGBA) + { + transforms |= PNG_TRANSFORM_STRIP_FILLER_AFTER; + } + + png_set_IHDR(png_ptr, info_ptr, m_width, m_height, m_bitDepth, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_compression_level(png_ptr, saveSettings.m_compressionLevel); @@ -259,14 +291,8 @@ namespace AZ } png_set_rows(png_ptr, info_ptr, rows.begin()); - - int transforms = PNG_TRANSFORM_IDENTITY; - if (saveSettings.m_stripAlpha && m_bufferFormat == PngFile::Format::RGBA) - { - transforms |= PNG_TRANSFORM_STRIP_FILLER_AFTER; - } - - png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + png_write_png(png_ptr, info_ptr, transforms, NULL); png_destroy_write_struct(&png_ptr, &info_ptr); diff --git a/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp b/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp new file mode 100644 index 0000000000..90181d8040 --- /dev/null +++ b/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp @@ -0,0 +1,327 @@ +/* + * 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 UnitTest +{ + using namespace AZ::Utils; + + class PngFileTests + : public AllocatorsFixture + { + protected: + AZStd::string m_testImageFolder; + AZStd::string m_tempPngFilePath; + AZStd::vector m_primaryColors3x1; + AZStd::unique_ptr m_localFileIO; + + void SetUp() override + { + AllocatorsFixture::SetUp(); + + m_testImageFolder = AZ::Test::GetEngineRootPath() + "/Gems/Atom/Utils/Code/Tests/PngTestImages/"; + m_tempPngFilePath = m_testImageFolder + "temp.png"; + + m_localFileIO.reset(aznew AZ::IO::LocalFileIO()); + AZ::IO::FileIOBase::SetInstance(m_localFileIO.get()); + + AZ::IO::FileIOBase::GetInstance()->Remove(m_tempPngFilePath.c_str()); + + m_primaryColors3x1 = { + 255u, 0u, 0u, 255u, + 0u, 255u, 0u, 255u, + 0u, 0u, 255u, 255u + }; + } + + void TearDown() override + { + m_testImageFolder = AZStd::string{}; + m_tempPngFilePath = AZStd::string{}; + m_primaryColors3x1 = AZStd::vector{}; + + AZ::IO::FileIOBase::SetInstance(nullptr); + m_localFileIO.reset(); + + AllocatorsFixture::TearDown(); + } + + struct Color3 : public AZStd::array + { + using Base = AZStd::array; + Color3(uint8_t r, uint8_t g, uint8_t b) : Base({r, g, b}) {} + Color3(const uint8_t* raw) : Base({raw[0], raw[1], raw[2]}) {} + }; + + struct Color4 : public AZStd::array + { + using Base = AZStd::array; + Color4(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : Base({r, g, b, a}) {} + Color4(const uint8_t* raw) : Base({raw[0], raw[1], raw[2], raw[3]}) {} + }; + }; + + TEST_F(PngFileTests, LoadRgb) + { + PngFile image = PngFile::Load((m_testImageFolder + "ColorChart_rgb.png").c_str()); + EXPECT_TRUE(image.IsValid()); + EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB); + EXPECT_EQ(image.GetWidth(), 3); + EXPECT_EQ(image.GetHeight(), 2); + EXPECT_EQ(image.GetBuffer().size(), 18); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 0), Color3(255u, 0u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 3), Color3(0u, 255u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 6), Color3(0u, 0u, 255u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 9), Color3(255u, 255u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 12), Color3(0u, 255u, 255u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 15), Color3(255u, 0u, 255u)); + } + + TEST_F(PngFileTests, LoadRgba) + { + PngFile image = PngFile::Load((m_testImageFolder + "ColorChart_rgba.png").c_str()); + EXPECT_TRUE(image.IsValid()); + EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGBA); + EXPECT_EQ(image.GetWidth(), 3); + EXPECT_EQ(image.GetHeight(), 2); + EXPECT_EQ(image.GetBuffer().size(), 24); + EXPECT_EQ(Color4(image.GetBuffer().begin() + 0), Color4(255u, 0u, 0u, 200u)); + EXPECT_EQ(Color4(image.GetBuffer().begin() + 4), Color4(0u, 255u, 0u, 150u)); + EXPECT_EQ(Color4(image.GetBuffer().begin() + 8), Color4(0u, 0u, 255u, 100u)); + EXPECT_EQ(Color4(image.GetBuffer().begin() + 12), Color4(255u, 255u, 0u, 125u)); + EXPECT_EQ(Color4(image.GetBuffer().begin() + 16), Color4(0u, 255u, 255u, 175u)); + EXPECT_EQ(Color4(image.GetBuffer().begin() + 20), Color4(255u, 0u, 255u, 75u)); + } + + TEST_F(PngFileTests, LoadRgbaStripAlpha) + { + PngFile::LoadSettings loadSettings; + loadSettings.m_stripAlpha = true; + + PngFile image = PngFile::Load((m_testImageFolder + "ColorChart_rgba.png").c_str(), loadSettings); + // Note these checks are identical to the LoadRgb test. + EXPECT_TRUE(image.IsValid()); + EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB); + EXPECT_EQ(image.GetWidth(), 3); + EXPECT_EQ(image.GetHeight(), 2); + EXPECT_EQ(image.GetBuffer().size(), 18); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 0), Color3(255u, 0u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 3), Color3(0u, 255u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 6), Color3(0u, 0u, 255u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 9), Color3(255u, 255u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 12), Color3(0u, 255u, 255u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 15), Color3(255u, 0u, 255u)); + } + + TEST_F(PngFileTests, LoadColorPaletteTwoBits) + { + PngFile image = PngFile::Load((m_testImageFolder + "ColorPalette_2bit.png").c_str()); + EXPECT_TRUE(image.IsValid()); + EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB); + EXPECT_EQ(image.GetWidth(), 1); + EXPECT_EQ(image.GetHeight(), 3); + EXPECT_EQ(image.GetBuffer().size(), 9); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 0), Color3(255u, 0u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 3), Color3(0u, 255u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 6), Color3(0u, 0u, 255u)); + } + + TEST_F(PngFileTests, LoadGrayscaleOneBit) + { + PngFile image = PngFile::Load((m_testImageFolder + "GrayPalette_1bit.png").c_str()); + EXPECT_TRUE(image.IsValid()); + EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB); + EXPECT_EQ(image.GetWidth(), 1); + EXPECT_EQ(image.GetHeight(), 2); + EXPECT_EQ(image.GetBuffer().size(), 6); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 0), Color3(0u, 0u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 3), Color3(255u, 255u, 255u)); + } + + TEST_F(PngFileTests, LoadRgba64Bits) + { + PngFile image = PngFile::Load((m_testImageFolder + "Gradient_rgb_16bpc.png").c_str()); + EXPECT_TRUE(image.IsValid()); + EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB); + EXPECT_EQ(image.GetWidth(), 5); + EXPECT_EQ(image.GetHeight(), 1); + EXPECT_EQ(image.GetBuffer().size(), 15); + // The values in this file are 30.0f, 30.1f, 30.2f, 30.3f, 30.4f. But we use PNG_TRANSFORM_STRIP_16 to reduce them to 8 bits per channel for simplicity. + EXPECT_EQ(Color3(image.GetBuffer().begin() + 0), Color3(76u, 0u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 3), Color3(77u, 0u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 6), Color3(77u, 0u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 9), Color3(77u, 0u, 0u)); + EXPECT_EQ(Color3(image.GetBuffer().begin() + 12), Color3(77u, 0u, 0u)); + } + + TEST_F(PngFileTests, CreateCopy) + { + AZStd::vector data = m_primaryColors3x1; + + PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, data); + EXPECT_TRUE(savedImage.IsValid()); + EXPECT_EQ(savedImage.GetWidth(), 3); + EXPECT_EQ(savedImage.GetHeight(), 1); + EXPECT_EQ(savedImage.GetBuffer(), data); + } + + TEST_F(PngFileTests, CreateMove) + { + AZStd::vector data = m_primaryColors3x1; + + PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, AZStd::move(data)); + EXPECT_TRUE(savedImage.IsValid()); + EXPECT_EQ(savedImage.GetWidth(), 3); + EXPECT_EQ(savedImage.GetHeight(), 1); + EXPECT_EQ(savedImage.GetBuffer(), m_primaryColors3x1); + EXPECT_TRUE(data.empty()); // The data should have been moved + } + + TEST_F(PngFileTests, SaveRgba) + { + PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, m_primaryColors3x1); + bool result = savedImage.Save(m_tempPngFilePath.c_str()); + EXPECT_TRUE(result); + + PngFile loadedImage = PngFile::Load(m_tempPngFilePath.c_str()); + EXPECT_TRUE(loadedImage.IsValid()); + EXPECT_EQ(loadedImage.GetBufferFormat(), savedImage.GetBufferFormat()); + EXPECT_EQ(loadedImage.GetWidth(), savedImage.GetWidth()); + EXPECT_EQ(loadedImage.GetHeight(), savedImage.GetHeight()); + EXPECT_EQ(loadedImage.GetBuffer(), savedImage.GetBuffer()); + } + + TEST_F(PngFileTests, SaveRgbaStripAlpha) + { + PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, m_primaryColors3x1); + + PngFile::SaveSettings saveSettings; + saveSettings.m_stripAlpha = true; + + bool result = savedImage.Save(m_tempPngFilePath.c_str(), saveSettings); + EXPECT_TRUE(result); + + // The alpha was stripped when saving. Now we load the data without stripping anything and should find + // that there is no alpha channel. + + PngFile loadedImage = PngFile::Load(m_tempPngFilePath.c_str()); + + // The dimensions are the same... + EXPECT_TRUE(loadedImage.IsValid()); + EXPECT_EQ(loadedImage.GetWidth(), savedImage.GetWidth()); + EXPECT_EQ(loadedImage.GetHeight(), savedImage.GetHeight()); + + // ... but the format is different + EXPECT_NE(loadedImage.GetBufferFormat(), savedImage.GetBufferFormat()); + EXPECT_EQ(loadedImage.GetBufferFormat(), PngFile::Format::RGB); + + // ... and the loaded data is smaller + EXPECT_NE(loadedImage.GetBuffer(), savedImage.GetBuffer()); + EXPECT_EQ(Color3(loadedImage.GetBuffer().begin() + 0), Color3(255u, 0u, 0u)); + EXPECT_EQ(Color3(loadedImage.GetBuffer().begin() + 3), Color3(0u, 255u, 0u)); + EXPECT_EQ(Color3(loadedImage.GetBuffer().begin() + 6), Color3(0u, 0u, 255u)); + } + + TEST_F(PngFileTests, Error_CreateUnsupportedFormat) + { + AZStd::vector data = m_primaryColors3x1; + + AZStd::string gotErrorMessage; + + PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R32_UINT, data, + [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }); + + EXPECT_FALSE(savedImage.IsValid()); + EXPECT_TRUE(gotErrorMessage.find("unsupported format R32_UINT") != AZStd::string::npos); + } + + TEST_F(PngFileTests, Error_CreateIncorrectBufferSize) + { + AZStd::vector data = m_primaryColors3x1; + + AZStd::string gotErrorMessage; + + PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 2, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, data, + [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }); + + EXPECT_FALSE(savedImage.IsValid()); + EXPECT_TRUE(gotErrorMessage.find("does not match") != AZStd::string::npos); + } + + TEST_F(PngFileTests, Error_LoadFileNotFound) + { + AZStd::string gotErrorMessage; + + PngFile::LoadSettings loadSettings; + loadSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }; + + PngFile image = PngFile::Load((m_testImageFolder + "DoesNotExist.png").c_str(), loadSettings); + EXPECT_FALSE(image.IsValid()); + EXPECT_TRUE(gotErrorMessage.find("not open file") != AZStd::string::npos); + } + + TEST_F(PngFileTests, Error_LoadEmptyFile) + { + AZStd::string gotErrorMessage; + + PngFile::LoadSettings loadSettings; + loadSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }; + + PngFile image = PngFile::Load((m_testImageFolder + "EmptyFile.png").c_str(), loadSettings); + EXPECT_FALSE(image.IsValid()); + EXPECT_TRUE(gotErrorMessage.find("Invalid png header") != AZStd::string::npos); + } + + TEST_F(PngFileTests, Error_LoadNotPngFile) + { + AZStd::string gotErrorMessage; + + PngFile::LoadSettings loadSettings; + loadSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }; + + PngFile image = PngFile::Load((m_testImageFolder + "ColorChart_rgba.jpg").c_str(), loadSettings); + EXPECT_FALSE(image.IsValid()); + EXPECT_TRUE(gotErrorMessage.find("Invalid png header") != AZStd::string::npos); + } + + TEST_F(PngFileTests, Error_SaveInvalidPngFile) + { + AZStd::string gotErrorMessage; + + PngFile::SaveSettings saveSettings; + saveSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }; + + PngFile savedImage; + bool result = savedImage.Save(m_tempPngFilePath.c_str(), saveSettings); + EXPECT_FALSE(result); + EXPECT_TRUE(gotErrorMessage.find("PngFile is invalid") != AZStd::string::npos); + EXPECT_FALSE(AZ::IO::FileIOBase::GetInstance()->Exists(m_tempPngFilePath.c_str())); + } + + TEST_F(PngFileTests, Error_SaveOverLockedFile) + { + AZStd::string gotErrorMessage; + + PngFile::SaveSettings saveSettings; + saveSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }; + + AZ::IO::FileIOStream tempFileStream; + tempFileStream.Open(m_tempPngFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath); + + PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, m_primaryColors3x1); + bool result = savedImage.Save(m_tempPngFilePath.c_str(), saveSettings); + EXPECT_FALSE(result); + EXPECT_TRUE(gotErrorMessage.find("not open file") != AZStd::string::npos); + } +} diff --git a/Gems/Atom/Utils/Code/Tests/PngTestImages/.gitignore b/Gems/Atom/Utils/Code/Tests/PngTestImages/.gitignore new file mode 100644 index 0000000000..ea08b96982 --- /dev/null +++ b/Gems/Atom/Utils/Code/Tests/PngTestImages/.gitignore @@ -0,0 +1 @@ +temp.png \ No newline at end of file diff --git a/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgb.png b/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgb.png new file mode 100644 index 0000000000..4dc14cc8eb --- /dev/null +++ b/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgb.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af0d0d079354495ff96aa266ecb4092d679e6c5a952e8b2d4ee743e538d54809 +size 126 diff --git a/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgba.jpg b/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgba.jpg new file mode 100644 index 0000000000..ea6f2283bd --- /dev/null +++ b/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgba.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01cad8dd75c9a26169e858960817424362c16cbf2a8df8bc55857f6172ce2526 +size 834 diff --git a/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgba.png b/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgba.png new file mode 100644 index 0000000000..943208e2cf --- /dev/null +++ b/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorChart_rgba.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ddb5f70eaf72fe09add6cc7cdf7cbba2d327ab312bb9bde73d7f456f80b8d6e +size 141 diff --git a/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorPalette_2bit.png b/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorPalette_2bit.png new file mode 100644 index 0000000000..38bdbc9755 --- /dev/null +++ b/Gems/Atom/Utils/Code/Tests/PngTestImages/ColorPalette_2bit.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b50e93bbbd320d69752df2c25b4118c0198226a0d230781a6ed93f89b7eea053 +size 142 diff --git a/Gems/Atom/Utils/Code/Tests/PngTestImages/EmptyFile.png b/Gems/Atom/Utils/Code/Tests/PngTestImages/EmptyFile.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Gems/Atom/Utils/Code/Tests/PngTestImages/Gradient_rgb_16bpc.png b/Gems/Atom/Utils/Code/Tests/PngTestImages/Gradient_rgb_16bpc.png new file mode 100644 index 0000000000..c28c2baf36 --- /dev/null +++ b/Gems/Atom/Utils/Code/Tests/PngTestImages/Gradient_rgb_16bpc.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb56e8bf15a4727bcebba579cb97a36e1f26e4a4870b2b4a38bdbd4b4bd076fd +size 127 diff --git a/Gems/Atom/Utils/Code/Tests/PngTestImages/GrayPalette_1bit.png b/Gems/Atom/Utils/Code/Tests/PngTestImages/GrayPalette_1bit.png new file mode 100644 index 0000000000..752e100691 --- /dev/null +++ b/Gems/Atom/Utils/Code/Tests/PngTestImages/GrayPalette_1bit.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:710fd5c80af49a42249a471ded6c9119be79d6748218073bb8297ffb4b4e62d1 +size 137 diff --git a/Gems/Atom/Utils/Code/atom_utils_tests_files.cmake b/Gems/Atom/Utils/Code/atom_utils_tests_files.cmake index 9069eeb682..5b43758a60 100644 --- a/Gems/Atom/Utils/Code/atom_utils_tests_files.cmake +++ b/Gems/Atom/Utils/Code/atom_utils_tests_files.cmake @@ -8,5 +8,6 @@ set(FILES Tests/ImageComparisonTests.cpp + Tests/PngFileTests.cpp Tests/StableDynamicArrayTests.cpp ) From e96793659a6c7926b054ba9d7f7b189dc3787c08 Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Fri, 10 Sep 2021 10:15:40 -0500 Subject: [PATCH 005/115] Fixes to get Mac & iOS building with new PNG support Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- .../Atom/Utils/Code/Include/Atom/Utils/PngFile.h | 6 ++++-- Gems/Atom/Utils/Code/Source/PngFile.cpp | 16 ++++++++-------- .../Platform/Mac/BuiltInPackages_mac.cmake | 2 +- .../Platform/iOS/BuiltInPackages_ios.cmake | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h index 7fb2c768ad..1de27e9b96 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/PngFile.h @@ -29,15 +29,17 @@ namespace AZ struct LoadSettings { - ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered + ErrorHandler m_errorHandler{}; //!< optional callback function describing any errors that are encountered bool m_stripAlpha = false; //!< the alpha channel will be skipped, loading an RGBA image as RGB + LoadSettings() {}; // clang errors out if this is not provided. }; struct SaveSettings { - ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered + ErrorHandler m_errorHandler{}; //!< optional callback function describing any errors that are encountered bool m_stripAlpha = false; //!< the alpha channel will be skipped, saving an RGBA buffer as RGB int m_compressionLevel = 6; //!< this is the zlib compression level. See png_set_compression_level in png.h + SaveSettings() {}; // clang errors out if this is not provided. }; // To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel. diff --git a/Gems/Atom/Utils/Code/Source/PngFile.cpp b/Gems/Atom/Utils/Code/Source/PngFile.cpp index 056e199d40..09a5d950e5 100644 --- a/Gems/Atom/Utils/Code/Source/PngFile.cpp +++ b/Gems/Atom/Utils/Code/Source/PngFile.cpp @@ -74,7 +74,8 @@ namespace AZ // For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 3 FILE* fp = NULL; - if (fopen_s(&fp, path, "rb") || !fp) + azfopen(&fp, path, "rb"); // return type differs across platforms so can't do inside if + if (!fp) { loadSettings.m_errorHandler("Cannot open file."); return {}; @@ -127,8 +128,7 @@ namespace AZ return {}; } -#pragma warning(push) -#pragma warning(disable: 4611) // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160 +AZ_PUSH_DISABLE_WARNING(4611, "-Wunknown-warning-option") // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160 if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); @@ -136,7 +136,7 @@ namespace AZ // We don't report an error message here because the user_error_fn should have done that already. return {}; } -#pragma warning(pop) +AZ_POP_DISABLE_WARNING png_init_io(png_ptr, fp); @@ -221,7 +221,8 @@ namespace AZ // For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 4 FILE* fp = NULL; - if (fopen_s(&fp, path, "wb") || !fp) + azfopen(&fp, path, "wb"); // return type differs across platforms so can't do inside if + if (!fp) { saveSettings.m_errorHandler("Cannot open file."); return false; @@ -248,8 +249,7 @@ namespace AZ return false; } -#pragma warning(push) -#pragma warning(disable: 4611) // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160 +AZ_PUSH_DISABLE_WARNING(4611, "-Wunknown-warning-option") // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160 if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); @@ -257,7 +257,7 @@ namespace AZ // We don't report an error message here because the user_error_fn should have done that already. return false; } -#pragma warning(pop) +AZ_POP_DISABLE_WARNING png_init_io(png_ptr, fp); diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index f64dbe82c7..f0ac0d6d54 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -39,7 +39,7 @@ ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-mac ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-mac TARGETS GoogleBenchmark PACKAGE_HASH ad25de0146769c91e179953d845de2bec8ed4a691f973f47e3eb37639381f665) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-mac TARGETS OpenSSL PACKAGE_HASH 28adc1c0616ac0482b2a9d7b4a3a3635a1020e87b163f8aba687c501cf35f96c) ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-mac TARGETS Qt PACKAGE_HASH 9d25918351898b308ded3e9e571fff6f26311b2071aeafd00dd5b249fdf53f7e) -ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 0000000000000000000000000000000000000000000000000000000000000000) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 1ad76cd038ccc1f288f83c5fe2859a0f35c5154e1fe7658e1230cc428d318a8b) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-mac TARGETS libsamplerate PACKAGE_HASH b912af40c0ac197af9c43d85004395ba92a6a859a24b7eacd920fed5854a97fe) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-mac TARGETS zlib PACKAGE_HASH 21714e8a6de4f2523ee92a7f52d51fbee29c5f37ced334e00dc3c029115b472e) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-mac TARGETS squish-ccr PACKAGE_HASH 155bfbfa17c19a9cd2ef025de14c5db598f4290045d5b0d83ab58cb345089a77) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index ec52936460..d152acfeae 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -25,7 +25,7 @@ ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-ios TARGETS PhysX ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-ios TARGETS mikkelsen PACKAGE_HASH 976aaa3ccd8582346132a10af253822ccc5d5bcc9ea5ba44d27848f65ee88a8a) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-ios TARGETS googletest PACKAGE_HASH 2f121ad9784c0ab73dfaa58e1fee05440a82a07cc556bec162eeb407688111a7) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-ios TARGETS GoogleBenchmark PACKAGE_HASH c2ffaed2b658892b1bcf81dee4b44cd1cb09fc78d55584ef5cb8ab87f2d8d1ae) -ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 0000000000000000000000000000000000000000000000000000000000000000) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-ios TARGETS libpng PACKAGE_HASH 18a8217721083c4dc46514105be43ca764fa9c994a74aa0b57766ea6f8187e7b) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-ios TARGETS libsamplerate PACKAGE_HASH 7656b961697f490d4f9c35d2e61559f6fc38c32102e542a33c212cd618fc2119) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-ios TARGETS OpenSSL PACKAGE_HASH cd0dfce3086a7172777c63dadbaf0ac3695b676119ecb6d0614b5fb1da03462f) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-ios TARGETS zlib PACKAGE_HASH a59fc0f83a02c616b679799310e9d86fde84514c6d2acefa12c6def0ae4a880c) From b44441b286c6d06b8489847bc1d41a50d2941f29 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 13 Sep 2021 17:19:22 -0700 Subject: [PATCH 006/115] Improved PngFile unit test a bit, added another check Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- Gems/Atom/Utils/Code/Tests/PngFileTests.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp b/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp index 90181d8040..2f3fb2c20c 100644 --- a/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp +++ b/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp @@ -318,6 +318,7 @@ namespace UnitTest AZ::IO::FileIOStream tempFileStream; tempFileStream.Open(m_tempPngFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath); + EXPECT_TRUE(tempFileStream.IsOpen()); PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, m_primaryColors3x1); bool result = savedImage.Save(m_tempPngFilePath.c_str(), saveSettings); From f99766f556bd1df07646015079884040198193c4 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 13 Sep 2021 22:06:08 -0700 Subject: [PATCH 007/115] Update unit test to use AZ::IO::Path. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- Gems/Atom/Utils/Code/Tests/PngFileTests.cpp | 32 +++++++++++---------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp b/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp index 2f3fb2c20c..4418358cd2 100644 --- a/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp +++ b/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace UnitTest @@ -21,8 +22,8 @@ namespace UnitTest : public AllocatorsFixture { protected: - AZStd::string m_testImageFolder; - AZStd::string m_tempPngFilePath; + AZ::IO::Path m_testImageFolder; + AZ::IO::Path m_tempPngFilePath; AZStd::vector m_primaryColors3x1; AZStd::unique_ptr m_localFileIO; @@ -30,9 +31,10 @@ namespace UnitTest { AllocatorsFixture::SetUp(); - m_testImageFolder = AZ::Test::GetEngineRootPath() + "/Gems/Atom/Utils/Code/Tests/PngTestImages/"; - m_tempPngFilePath = m_testImageFolder + "temp.png"; + m_testImageFolder = AZ::IO::Path(AZ::Test::GetEngineRootPath()) / AZ::IO::Path("Gems/Atom/Utils/Code/Tests/PngTestImages", '/'); + m_tempPngFilePath = m_testImageFolder / "temp.png"; + m_localFileIO.reset(aznew AZ::IO::LocalFileIO()); AZ::IO::FileIOBase::SetInstance(m_localFileIO.get()); @@ -47,8 +49,8 @@ namespace UnitTest void TearDown() override { - m_testImageFolder = AZStd::string{}; - m_tempPngFilePath = AZStd::string{}; + m_testImageFolder = AZ::IO::Path{}; + m_tempPngFilePath = AZ::IO::Path{}; m_primaryColors3x1 = AZStd::vector{}; AZ::IO::FileIOBase::SetInstance(nullptr); @@ -74,7 +76,7 @@ namespace UnitTest TEST_F(PngFileTests, LoadRgb) { - PngFile image = PngFile::Load((m_testImageFolder + "ColorChart_rgb.png").c_str()); + PngFile image = PngFile::Load((m_testImageFolder / "ColorChart_rgb.png").c_str()); EXPECT_TRUE(image.IsValid()); EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB); EXPECT_EQ(image.GetWidth(), 3); @@ -90,7 +92,7 @@ namespace UnitTest TEST_F(PngFileTests, LoadRgba) { - PngFile image = PngFile::Load((m_testImageFolder + "ColorChart_rgba.png").c_str()); + PngFile image = PngFile::Load((m_testImageFolder / "ColorChart_rgba.png").c_str()); EXPECT_TRUE(image.IsValid()); EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGBA); EXPECT_EQ(image.GetWidth(), 3); @@ -109,7 +111,7 @@ namespace UnitTest PngFile::LoadSettings loadSettings; loadSettings.m_stripAlpha = true; - PngFile image = PngFile::Load((m_testImageFolder + "ColorChart_rgba.png").c_str(), loadSettings); + PngFile image = PngFile::Load((m_testImageFolder / "ColorChart_rgba.png").c_str(), loadSettings); // Note these checks are identical to the LoadRgb test. EXPECT_TRUE(image.IsValid()); EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB); @@ -126,7 +128,7 @@ namespace UnitTest TEST_F(PngFileTests, LoadColorPaletteTwoBits) { - PngFile image = PngFile::Load((m_testImageFolder + "ColorPalette_2bit.png").c_str()); + PngFile image = PngFile::Load((m_testImageFolder / "ColorPalette_2bit.png").c_str()); EXPECT_TRUE(image.IsValid()); EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB); EXPECT_EQ(image.GetWidth(), 1); @@ -139,7 +141,7 @@ namespace UnitTest TEST_F(PngFileTests, LoadGrayscaleOneBit) { - PngFile image = PngFile::Load((m_testImageFolder + "GrayPalette_1bit.png").c_str()); + PngFile image = PngFile::Load((m_testImageFolder / "GrayPalette_1bit.png").c_str()); EXPECT_TRUE(image.IsValid()); EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB); EXPECT_EQ(image.GetWidth(), 1); @@ -151,7 +153,7 @@ namespace UnitTest TEST_F(PngFileTests, LoadRgba64Bits) { - PngFile image = PngFile::Load((m_testImageFolder + "Gradient_rgb_16bpc.png").c_str()); + PngFile image = PngFile::Load((m_testImageFolder / "Gradient_rgb_16bpc.png").c_str()); EXPECT_TRUE(image.IsValid()); EXPECT_EQ(image.GetBufferFormat(), PngFile::Format::RGB); EXPECT_EQ(image.GetWidth(), 5); @@ -266,7 +268,7 @@ namespace UnitTest PngFile::LoadSettings loadSettings; loadSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }; - PngFile image = PngFile::Load((m_testImageFolder + "DoesNotExist.png").c_str(), loadSettings); + PngFile image = PngFile::Load((m_testImageFolder / "DoesNotExist.png").c_str(), loadSettings); EXPECT_FALSE(image.IsValid()); EXPECT_TRUE(gotErrorMessage.find("not open file") != AZStd::string::npos); } @@ -278,7 +280,7 @@ namespace UnitTest PngFile::LoadSettings loadSettings; loadSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }; - PngFile image = PngFile::Load((m_testImageFolder + "EmptyFile.png").c_str(), loadSettings); + PngFile image = PngFile::Load((m_testImageFolder / "EmptyFile.png").c_str(), loadSettings); EXPECT_FALSE(image.IsValid()); EXPECT_TRUE(gotErrorMessage.find("Invalid png header") != AZStd::string::npos); } @@ -290,7 +292,7 @@ namespace UnitTest PngFile::LoadSettings loadSettings; loadSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }; - PngFile image = PngFile::Load((m_testImageFolder + "ColorChart_rgba.jpg").c_str(), loadSettings); + PngFile image = PngFile::Load((m_testImageFolder / "ColorChart_rgba.jpg").c_str(), loadSettings); EXPECT_FALSE(image.IsValid()); EXPECT_TRUE(gotErrorMessage.find("Invalid png header") != AZStd::string::npos); } From c61fc4f67c381dce718990dd9f42e69698f59bc2 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 13 Sep 2021 22:08:25 -0700 Subject: [PATCH 008/115] Removed Error_SaveOverLockedFile because it was failing on mac for some file system reason. This particular test case wasn't that important so it wasn't worth digging into, especially since I don't have a mac handy. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- Gems/Atom/Utils/Code/Tests/PngFileTests.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp b/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp index 4418358cd2..1c5b844204 100644 --- a/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp +++ b/Gems/Atom/Utils/Code/Tests/PngFileTests.cpp @@ -310,21 +310,4 @@ namespace UnitTest EXPECT_TRUE(gotErrorMessage.find("PngFile is invalid") != AZStd::string::npos); EXPECT_FALSE(AZ::IO::FileIOBase::GetInstance()->Exists(m_tempPngFilePath.c_str())); } - - TEST_F(PngFileTests, Error_SaveOverLockedFile) - { - AZStd::string gotErrorMessage; - - PngFile::SaveSettings saveSettings; - saveSettings.m_errorHandler = [&gotErrorMessage](const char* errorMessage) { gotErrorMessage = errorMessage; }; - - AZ::IO::FileIOStream tempFileStream; - tempFileStream.Open(m_tempPngFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath); - EXPECT_TRUE(tempFileStream.IsOpen()); - - PngFile savedImage = PngFile::Create(AZ::RHI::Size{3, 1, 0}, AZ::RHI::Format::R8G8B8A8_UNORM, m_primaryColors3x1); - bool result = savedImage.Save(m_tempPngFilePath.c_str(), saveSettings); - EXPECT_FALSE(result); - EXPECT_TRUE(gotErrorMessage.find("not open file") != AZStd::string::npos); - } } From 125bcc1b473f98ffa87d858985486d25e1ac5e59 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 12:13:19 +0100 Subject: [PATCH 009/115] Provisional impl and testing of central state tracker. Signed-off-by: John --- .../ViewportEditorModeStateTrackerInterface.h | 42 ++ ...ortEditorModeStateTrackerNotificationBus.h | 65 +++ .../EditorInteractionInterface.h | 33 ++ .../ViewportEditorModeStateTracker.cpp | 121 +++++ .../ViewportEditorModeStateTracker.h | 62 +++ .../aztoolsframework_files.cmake | 4 + .../Viewport/ViewportEditorModeTests.cpp | 492 ++++++++++++++++++ .../Tests/aztoolsframeworktests_files.cmake | 1 + 8 files changed, 820 insertions(+) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h create mode 100644 Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h new file mode 100644 index 0000000000..4f8b800215 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h @@ -0,0 +1,42 @@ +/* + * 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 + +namespace AzToolsFramework +{ + //! The AZ::Interface of the central editor mode state tracker for all viewports. + class ViewportEditorModeStateTrackerInterface + { + public: + AZ_RTTI(ViewportEditorModeStateTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); + + virtual ~ViewportEditorModeStateTrackerInterface() = default; + + //! Enters the specified editor mode for the specified viewport. + virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + + //! Exits the specified editor mode for the specified viewport. + virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + + //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. + virtual const ViewportEditorModeStateInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + + //! Returns the number of viewports currently being tracked. + virtual size_t GetNumTrackedViewports() const = 0; + + //! Returns true if the specified viewport is being tracked, otherwise false. + virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + + private: + }; +} // namespace AzToolsFramework + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h new file mode 100644 index 0000000000..7b95ebc6cc --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h @@ -0,0 +1,65 @@ +/* + * 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 AzToolsFramework +{ + //! Enumeration of each viewport editor state. + enum class ViewportEditorMode : AZ::u8 + { + Default, + Component, + Focus, + Pick + }; + + //! Viewport identifier and other relevant viewport data. + struct ViewportEditorModeInfo + { + using IdType = AzFramework::ViewportId; + IdType m_id = ViewportUi::DefaultViewportId; //!< The unique identifier for a given viewport. + }; + + //! Interface for the editor mode state of a given viewport. + class ViewportEditorModeStateInterface + { + public: + virtual ~ViewportEditorModeStateInterface() = default; + + //! Returns true if the specified editor mode is active, otherwise false. + virtual bool IsModeActive(ViewportEditorMode mode) const = 0; + }; + + //! Provides a bus to notify when the different editor modes are entered/exit. + class ViewportEditorModeNotifications + : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; + using BusIdType = ViewportEditorModeInfo::IdType; + ////////////////////////////////////////////////////////////////////////// + + //! Notifies subscribers of the a given viewport to the entering of the specified editor mode. + virtual void OnEditorModeEnter([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + { + } + + //! Notifies subscribers of the a given viewport to the exiting of the specified editor mode. + virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + { + } + }; + using ViewportEditorModeNotificationsBus = AZ::EBus; +} diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h new file mode 100644 index 0000000000..70cbfd09ec --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h @@ -0,0 +1,33 @@ +/* + * 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 + +namespace AzToolsFramework +{ + /*! + * EditorInteractionInterface + * Allows systems to alter the behavior of viewport selection. + */ + class EditorInteractionInterface + { + public: + AZ_RTTI(EditorInteractionInterface, "{09276E3C-9AA6-40FF-A0B5-3D33A33F0E5A}"); + + /*! + * Allows the entity system to redirect the selection of an entity to another entity. + * It can be used to select a container when clicking on its content. + */ + virtual AZ::EntityId RedirectEntitySelection(AZ::EntityId entityId) = 0; + }; + +} // namespace AzToolsFramework + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp new file mode 100644 index 0000000000..64e8c2bbd1 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp @@ -0,0 +1,121 @@ +/* + * 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 AzToolsFramework +{ + static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; + + void ViewportEditorModeState::SetModeActive(ViewportEditorMode mode) + { + if (const AZ::u32 modeIndex = static_cast(mode); + modeIndex < NumEditorModes) + { + m_editorModes[modeIndex] = true; + } + else + { + AZ_Error(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex) + } + } + + void ViewportEditorModeState::SetModeInactive(ViewportEditorMode mode) + { + if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) + { + m_editorModes[modeIndex] = false; + } + else + { + AZ_Error(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex) + } + } + + bool ViewportEditorModeState::IsModeActive(ViewportEditorMode mode) const + { + return m_editorModes[static_cast(mode)]; + } + + void ViewportEditorModeStateTracker::RegisterInterface() + { + if (AZ::Interface::Get() == nullptr) + { + AZ::Interface::Register(this); + } + } + + void ViewportEditorModeStateTracker::UnregisterInterface() + { + if (AZ::Interface::Get() != nullptr) + { + AZ::Interface::Unregister(this); + } + } + + void ViewportEditorModeStateTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + { + auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + AZ_Warning( + ViewportEditorModeLogWindow, !editorModeStates.IsModeActive(mode), + AZStd::string::format( + "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + editorModeStates.SetModeActive(mode); + ViewportEditorModeNotificationsBus::Event( + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); + } + + void ViewportEditorModeStateTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + { + ViewportEditorModeState* editorModeStates = nullptr; + if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) + { + editorModeStates = &m_viewportEditorModeStates.at(viewportEditorModeInfo.m_id); + AZ_Warning( + ViewportEditorModeLogWindow, editorModeStates->IsModeActive(mode), + AZStd::string::format( + "Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + } + else + { + AZ_Warning( + ViewportEditorModeLogWindow, false, "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", + static_cast(mode), viewportEditorModeInfo.m_id); + + editorModeStates = &m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + } + + editorModeStates->SetModeInactive(mode); + ViewportEditorModeNotificationsBus::Event( + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); + } + + const ViewportEditorModeStateInterface* ViewportEditorModeStateTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + { + if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); + editorModeStates != m_viewportEditorModeStates.end()) + { + return &editorModeStates->second; + } + else + { + return nullptr; + } + } + + size_t ViewportEditorModeStateTracker::GetNumTrackedViewports() const + { + return m_viewportEditorModeStates.size(); + } + + bool ViewportEditorModeStateTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + { + return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; + } +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h new file mode 100644 index 0000000000..30eabdf16e --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.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 +#include +#include +#include +#include + +namespace AzToolsFramework +{ + //! The encapsulation of the editor modes for a given viewport. + class ViewportEditorModeState + : public ViewportEditorModeStateInterface + { + public: + + //! The number of currently supported viewport editor modes. + static constexpr AZ::u8 NumEditorModes = 4; + + //! Sets the specified mode as active. + void SetModeActive(ViewportEditorMode mode); + + // Sets the specified mode as inactive. + void SetModeInactive(ViewportEditorMode mode); + + // ViewportEditorModeStateInterface ... + bool IsModeActive(ViewportEditorMode mode) const override; + private: + AZStd::array m_editorModes{}; //!< State flags to track active/inactive status of viewport editor modes. + }; + + //! The implementation of the central editor mode state tracker for all viewports. + class ViewportEditorModeStateTracker + : public ViewportEditorModeStateTrackerInterface + { + public: + //! Registers this object with the AZ::Interface. + void RegisterInterface(); + + //! Unregisters this object with the AZ::Interface. + void UnregisterInterface(); + + // ViewportEditorModeStateTrackerInterface ... + void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + const ViewportEditorModeStateInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + size_t GetNumTrackedViewports() const override; + bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + + private: + using ViewportEditorModeStates = AZStd::unordered_map; + ViewportEditorModeStates m_viewportEditorModeStates; //!< Editor mode state per viewport. + }; +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 2d9e75a115..9b7394a6e7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -34,6 +34,7 @@ set(FILES API/EditorAnimationSystemRequestBus.h API/EditorEntityAPI.h API/EditorLevelNotificationBus.h + API/ViewportEditorModeStateTrackerNotificationBus.h API/EditorVegetationRequestsBus.h API/EditorPythonConsoleBus.h API/EditorPythonRunnerRequestsBus.h @@ -44,6 +45,7 @@ set(FILES API/EntityCompositionNotificationBus.h API/EditorViewportIconDisplayInterface.h API/ViewPaneOptions.h + API/ViewportEditorModeStateTrackerInterface.h Application/Ticker.h Application/Ticker.cpp Application/EditorEntityManager.cpp @@ -538,6 +540,8 @@ set(FILES ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp ViewportSelection/EditorVisibleEntityDataCache.h ViewportSelection/EditorVisibleEntityDataCache.cpp + ViewportSelection/ViewportEditorModeStateTracker.cpp + ViewportSelection/ViewportEditorModeStateTracker.h ToolsFileUtils/ToolsFileUtils.h AssetBrowser/AssetBrowserBus.h AssetBrowser/AssetBrowserSourceDropBus.h diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp new file mode 100644 index 0000000000..7718c596d5 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -0,0 +1,492 @@ +/* + * 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 +{ + using ViewportEditorMode = AzToolsFramework::ViewportEditorMode; + using ViewportEditorModeState = AzToolsFramework::ViewportEditorModeState; + using ViewportEditorModeStateTracker = AzToolsFramework::ViewportEditorModeStateTracker; + using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo; + using ViewportId = ViewportEditorModeInfo::IdType; + using ViewportEditorModeStateInterface = AzToolsFramework::ViewportEditorModeStateInterface; + + void SetAllModesActive(ViewportEditorModeState& editorModeState) + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + editorModeState.SetModeActive(static_cast(mode)); + } + } + + void SetAllModesInactive(ViewportEditorModeState& editorModeState) + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + editorModeState.SetModeInactive(static_cast(mode)); + } + } + + // Fixture for testing editor mode states + class ViewportEditorModeStateTestsFixture + : public ::testing::Test + { + public: + ViewportEditorModeState m_editorModeState; + }; + + // Fixture for testing editor mode states with parameterized test arguments + class ViewportEditorModeStateTestsFixtureWithParams + : public ViewportEditorModeStateTestsFixture + , public ::testing::WithParamInterface + { + public: + void SetUp() override + { + m_selectedEditorMode = GetParam(); + } + + ViewportEditorMode m_selectedEditorMode; + }; + + // Fixture for testing the viewport editor mode state tracker + class ViewportEditorModeStateTrackerTestFixture + : public ToolsApplicationFixture + { + public: + ViewportEditorModeStateTracker m_viewportEditorModeStteTracker; + }; + + // Subscriber of viewport editor mode notifications for a single viewport that expects a single mode to be activated/deactivated + class ViewportEditorModeNotificationsBusHandler + : private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler + { + public: + struct ReceivedEvents + { + bool m_onEnter = false; + bool m_onLeave = false; + }; + + using EditModeTracker = AZStd::unordered_map; + + ViewportEditorModeNotificationsBusHandler(ViewportId viewportId) + : m_viewportSubscription(viewportId) + { + AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusConnect(m_viewportSubscription); + } + + ~ViewportEditorModeNotificationsBusHandler() + { + AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); + } + + ViewportId GetViewportSubscription() const + { + return m_viewportSubscription; + } + + const EditModeTracker& GetEditorModes() const + { + return m_editorModes; + } + + void OnEditorModeEnter([[maybe_unused]]const ViewportEditorModeStateInterface& editorModeState, ViewportEditorMode mode) override + { + m_editorModes[mode].m_onEnter = true; + } + + virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, ViewportEditorMode mode) override + { + m_editorModes[mode].m_onLeave = true; + } + + private: + ViewportId m_viewportSubscription; + EditModeTracker m_editorModes; + + }; + + // Fixture for testing viewport editor mode notifications publishing + class ViewportEditorModePublisherTestFixture + : public ViewportEditorModeStateTrackerTestFixture + { + public: + + void SetUpEditorFixtureImpl() override + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + m_editorModeHandlers[mode] = AZStd::make_unique(mode); + } + } + + void TearDownEditorFixtureImpl() override + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + m_editorModeHandlers[mode].reset(); + } + } + + AZStd::array, ViewportEditorModeState::NumEditorModes> m_editorModeHandlers; + }; + + TEST_F(ViewportEditorModeStateTestsFixture, NumberOfEditorModesIsEqualTo4) + { + EXPECT_EQ(ViewportEditorModeState::NumEditorModes, 4); + } + + TEST_F(ViewportEditorModeStateTestsFixture, InitialEditorModeStateHasAllInactiveModes) + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + EXPECT_FALSE(m_editorModeState.IsModeActive(static_cast(mode))); + } + } + + TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) + { + m_editorModeState.SetModeActive(m_selectedEditorMode); + + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + const auto editorMode = static_cast(mode); + if (editorMode == m_selectedEditorMode) + { + EXPECT_TRUE(m_editorModeState.IsModeActive(static_cast(editorMode))); + } + else + { + EXPECT_FALSE(m_editorModeState.IsModeActive(static_cast(editorMode))); + } + } + } + + TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) + { + SetAllModesActive(m_editorModeState); + m_editorModeState.SetModeInactive(m_selectedEditorMode); + + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + const auto editorMode = static_cast(mode); + if (editorMode == m_selectedEditorMode) + { + EXPECT_FALSE(m_editorModeState.IsModeActive(editorMode)); + } + else + { + EXPECT_TRUE(m_editorModeState.IsModeActive(editorMode)); + } + } + } + + TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively) + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes - 1; mode++) + { + // Given only the selected mode active + SetAllModesInactive(m_editorModeState); + m_editorModeState.SetModeActive(m_selectedEditorMode); + + const auto editorMode = static_cast(mode); + if (editorMode == m_selectedEditorMode) + { + continue; + } + + // When other modes are activated + m_editorModeState.SetModeActive(editorMode); + + for (auto expectedMode = 0; expectedMode < ViewportEditorModeState::NumEditorModes; expectedMode++) + { + const auto expectedEditorMode = static_cast(expectedMode); + if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) + { + // Expect the activated modes to be active + EXPECT_TRUE(m_editorModeState.IsModeActive(expectedEditorMode)); + } + else + { + // Expect the modes not active to be inactive + EXPECT_FALSE(m_editorModeState.IsModeActive(expectedEditorMode)); + } + } + } + } + + TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingMultipleModesInactiveInactivatesAllThoseModesNonMutuallyExclusively) + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes - 1; mode++) + { + // Given only the selected mode inactive + SetAllModesActive(m_editorModeState); + m_editorModeState.SetModeInactive(m_selectedEditorMode); + + const auto editorMode = static_cast(mode); + if (editorMode == m_selectedEditorMode) + { + continue; + } + + // When other modes are deactivated + m_editorModeState.SetModeInactive(editorMode); + + for (auto expectedMode = 0; expectedMode < ViewportEditorModeState::NumEditorModes; expectedMode++) + { + const auto expectedEditorMode = static_cast(expectedMode); + if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) + { + // Expect the deactivated modes to be inactive + EXPECT_FALSE(m_editorModeState.IsModeActive(expectedEditorMode)); + } + else + { + // Expects the modes not deactivated to still be active + EXPECT_TRUE(m_editorModeState.IsModeActive(expectedEditorMode)); + } + } + } + } + + INSTANTIATE_TEST_CASE_P( + AllEditorModes, + ViewportEditorModeStateTestsFixtureWithParams, + ::testing::Values( + AzToolsFramework::ViewportEditorMode::Default, + AzToolsFramework::ViewportEditorMode::Component, + AzToolsFramework::ViewportEditorMode::Focus, + AzToolsFramework::ViewportEditorMode::Pick)); + + TEST_F(ViewportEditorModeStateTestsFixture, SettingOutOfBoundsModeActiveIssuesErrorMsg) + { + UnitTest::TestRunner::Instance().StartAssertTests(); + m_editorModeState.SetModeActive(static_cast(ViewportEditorModeState::NumEditorModes)); + EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); + } + + TEST_F(ViewportEditorModeStateTestsFixture, SettingOutOfBoundsModeInactiveIssuesErrorMsg) + { + UnitTest::TestRunner::Instance().StartAssertTests(); + m_editorModeState.SetModeInactive(static_cast(ViewportEditorModeState::NumEditorModes)); + EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModeStates) + { + EXPECT_EQ(m_viewportEditorModeStteTracker.GetNumTrackedViewports(), 0); + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModeStateForThatId) + { + // Given a viewport not currently being tracked + const ViewportId viewportid = 0; + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + + // When a mode is activated for that viewport + const auto editorMode = ViewportEditorMode::Default; + m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + + // Expect that viewport to now be tracked + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_NE(viewportEditorModeState, nullptr); + + // Expect the mode for that viewport to be active + EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModeStateForThatIdButIssuesErrorMsg) + { + // Given a viewport not currently being tracked + const ViewportId viewportid = 0; + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + + // When a mode is deactivated for that viewport + const auto editorMode = ViewportEditorMode::Default; + UnitTest::ErrorHandler errorHandler(AZStd::string::format( + "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", static_cast(editorMode), viewportid).c_str()); + m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + + // Expect a warning to be issued due to no precursor activation of that mode + EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + + // Expect that viewport to now be tracked + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + + // Expect the mode for that viewport to be inactive + EXPECT_NE(viewportEditorModeState, nullptr); + EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, GettingNonExistentViewportEditorModeStateForIdReturnsNull) + { + const ViewportId viewportid = 0; + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, EnteringViewportEditorModeStateForExistingIdInThatStateIssuesWarningMsg) + { + // Given a viewport not currently tracked + const ViewportId viewportid = 0; + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + + const auto editorMode = ViewportEditorMode::Default; + const auto expectedWarning = AZStd::string::format( + "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + + { + UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); + + // When the mode is activated for the viewport + m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + + // Expect no warning to be issued as there is no duplicate activation + EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); + + // Expect the mode to be active for the viewport + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_NE(viewportEditorModeState, nullptr); + EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); + } + { + // When the mode is activated again for the viewport + UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); + m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + + // Expect a warning to be issued for the duplicate activation + EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + + // Expect the mode to still be active for the viewport + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_NE(viewportEditorModeState, nullptr); + EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); + } + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, ExitingViewportEditorModeStateForExistingIdNotInThatStateIssuesWarningMsg) + { + // Given a viewport not currently tracked + const ViewportId viewportid = 0; + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + + const auto editorMode = ViewportEditorMode::Default; + const auto expectedWarning = + AZStd::string::format("Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + + { + UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); + + // When the mode is activated and then deactivated for the viewport + m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + + // Expect no warning to be issued as there is no duplicate deactivation + EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); + + // Expect the mode to be inctive for the viewport + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_NE(viewportEditorModeState, nullptr); + EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); + } + { + UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); + + // When the mode is deactivated again for the viewport + m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + + // Expect a warning to be issued for the duplicate deactivation + EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + + // Expect the mode to still be inactive for the viewport + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_NE(viewportEditorModeState, nullptr); + EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); + } + } + + TEST_F( + ViewportEditorModePublisherTestFixture, + EnteringViewportEditorModeStateForExistingIdPublishesOnViewportEditorModeEnterEventForAllSubscribers) + { + // Given a set of subscribers tracking the editor modes for their exclusive viewport + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + // Expect each subscriber to have received no editor mode state changes + EXPECT_EQ(m_editorModeHandlers[mode]->GetEditorModes().size(), 0); + } + + // When each editor mode is activated by the state tracker for a specific viewport + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + const ViewportId viewportId = mode; + const ViewportEditorMode editorMode = static_cast(mode); + m_viewportEditorModeStteTracker.EnterMode({ mode }, editorMode); + } + + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + // Expect only the subscribers of each viewport to have received the editor mode activated event + const ViewportEditorMode editorMode = static_cast(mode); + const auto& editorModes = m_editorModeHandlers[mode]->GetEditorModes(); + EXPECT_EQ(editorModes.size(), 1); + EXPECT_EQ(editorModes.count(editorMode), 1); + const auto& expectedEditorModeSet = editorModes.find(editorMode); + EXPECT_NE(expectedEditorModeSet, editorModes.end()); + EXPECT_TRUE(expectedEditorModeSet->second.m_onEnter); + EXPECT_FALSE(expectedEditorModeSet->second.m_onLeave); + } + } + + TEST_F( + ViewportEditorModePublisherTestFixture, + ExitingViewportEditorModeStateForExistingIdPublishesOnViewportEditorModeExitEventForAllSubscribers) + { + // Given a set of subscribers tracking the editor modes for their exclusive viewport + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + EXPECT_EQ(m_editorModeHandlers[mode]->GetEditorModes().size(), 0); + } + + // When each editor mode is activated deactivated by the state tracker for a specific viewport + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + const ViewportId viewportId = mode; + const ViewportEditorMode editorMode = static_cast(mode); + m_viewportEditorModeStteTracker.EnterMode({ mode }, editorMode); + m_viewportEditorModeStteTracker.ExitMode({ mode }, editorMode); + } + + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + // Expect only the subscribers of each viewport to have received the editor mode activated and deactivated event + const ViewportEditorMode editorMode = static_cast(mode); + const auto& editorModes = m_editorModeHandlers[mode]->GetEditorModes(); + EXPECT_EQ(editorModes.size(), 1); + EXPECT_EQ(editorModes.count(editorMode), 1); + const auto& expectedEditorModeSet = editorModes.find(editorMode); + EXPECT_NE(expectedEditorModeSet, editorModes.end()); + EXPECT_TRUE(expectedEditorModeSet->second.m_onEnter); + EXPECT_TRUE(expectedEditorModeSet->second.m_onLeave); + } + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake index 5ff41d9e6c..764afce266 100644 --- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake +++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake @@ -110,6 +110,7 @@ set(FILES UI/EntityPropertyEditorTests.cpp UndoStack.cpp Viewport/ClusterTests.cpp + Viewport/ViewportEditorModeTests.cpp Viewport/ViewportScreenTests.cpp Viewport/ViewportUiClusterTests.cpp Viewport/ViewportUiDisplayTests.cpp From 02425f85772fdc31a72834669b9695ec78e0b378 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 12:21:36 +0100 Subject: [PATCH 010/115] Add missing namespace comment. Signed-off-by: John --- .../AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 7718c596d5..cae7092a8a 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -489,4 +489,4 @@ namespace UnitTest EXPECT_TRUE(expectedEditorModeSet->second.m_onLeave); } } -} +} // namespace UnitTest From 199d857c8a447796176b959d3c5f5134ad74b1df Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 17:51:23 +0100 Subject: [PATCH 011/115] ViewportEditorModeState -> ViewportEditorModes Signed-off-by: John --- ... => ViewportEditorModesTrackerInterface.h} | 10 +- ...ewportEditorModesTrackerNotificationBus.h} | 8 +- ...ker.cpp => ViewportEditorModesTracker.cpp} | 34 +++--- ...Tracker.h => ViewportEditorModesTracker.h} | 22 ++-- .../aztoolsframework_files.cmake | 8 +- .../Viewport/ViewportEditorModeTests.cpp | 106 +++++++++--------- 6 files changed, 94 insertions(+), 94 deletions(-) rename Code/Framework/AzToolsFramework/AzToolsFramework/API/{ViewportEditorModeStateTrackerInterface.h => ViewportEditorModesTrackerInterface.h} (74%) rename Code/Framework/AzToolsFramework/AzToolsFramework/API/{ViewportEditorModeStateTrackerNotificationBus.h => ViewportEditorModesTrackerNotificationBus.h} (88%) rename Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/{ViewportEditorModeStateTracker.cpp => ViewportEditorModesTracker.cpp} (68%) rename Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/{ViewportEditorModeStateTracker.h => ViewportEditorModesTracker.h} (68%) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h similarity index 74% rename from Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h index 4f8b800215..b13085bc83 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h @@ -9,17 +9,17 @@ #pragma once #include -#include +#include namespace AzToolsFramework { //! The AZ::Interface of the central editor mode state tracker for all viewports. - class ViewportEditorModeStateTrackerInterface + class ViewportEditorModesTrackerInterface { public: - AZ_RTTI(ViewportEditorModeStateTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); + AZ_RTTI(ViewportEditorModesTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); - virtual ~ViewportEditorModeStateTrackerInterface() = default; + virtual ~ViewportEditorModesTrackerInterface() = default; //! Enters the specified editor mode for the specified viewport. virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; @@ -28,7 +28,7 @@ namespace AzToolsFramework virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. - virtual const ViewportEditorModeStateInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + virtual const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; //! Returns the number of viewports currently being tracked. virtual size_t GetNumTrackedViewports() const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerNotificationBus.h similarity index 88% rename from Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerNotificationBus.h index 7b95ebc6cc..b9b5c80f39 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerNotificationBus.h @@ -30,10 +30,10 @@ namespace AzToolsFramework }; //! Interface for the editor mode state of a given viewport. - class ViewportEditorModeStateInterface + class ViewportEditorModesInterface { public: - virtual ~ViewportEditorModeStateInterface() = default; + virtual ~ViewportEditorModesInterface() = default; //! Returns true if the specified editor mode is active, otherwise false. virtual bool IsModeActive(ViewportEditorMode mode) const = 0; @@ -52,12 +52,12 @@ namespace AzToolsFramework ////////////////////////////////////////////////////////////////////////// //! Notifies subscribers of the a given viewport to the entering of the specified editor mode. - virtual void OnEditorModeEnter([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeEnter([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } //! Notifies subscribers of the a given viewport to the exiting of the specified editor mode. - virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp similarity index 68% rename from Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp rename to Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp index 64e8c2bbd1..5e6f73f963 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp @@ -6,14 +6,14 @@ * */ -#include -#include +#include +#include namespace AzToolsFramework { static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; - void ViewportEditorModeState::SetModeActive(ViewportEditorMode mode) + void ViewportEditorModes::SetModeActive(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) @@ -26,7 +26,7 @@ namespace AzToolsFramework } } - void ViewportEditorModeState::SetModeInactive(ViewportEditorMode mode) + void ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) { @@ -38,28 +38,28 @@ namespace AzToolsFramework } } - bool ViewportEditorModeState::IsModeActive(ViewportEditorMode mode) const + bool ViewportEditorModes::IsModeActive(ViewportEditorMode mode) const { return m_editorModes[static_cast(mode)]; } - void ViewportEditorModeStateTracker::RegisterInterface() + void ViewportEditorModesTracker::RegisterInterface() { - if (AZ::Interface::Get() == nullptr) + if (AZ::Interface::Get() == nullptr) { - AZ::Interface::Register(this); + AZ::Interface::Register(this); } } - void ViewportEditorModeStateTracker::UnregisterInterface() + void ViewportEditorModesTracker::UnregisterInterface() { - if (AZ::Interface::Get() != nullptr) + if (AZ::Interface::Get() != nullptr) { - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); } } - void ViewportEditorModeStateTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModesTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; AZ_Warning( @@ -71,9 +71,9 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); } - void ViewportEditorModeStateTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModesTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { - ViewportEditorModeState* editorModeStates = nullptr; + ViewportEditorModes* editorModeStates = nullptr; if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) { editorModeStates = &m_viewportEditorModeStates.at(viewportEditorModeInfo.m_id); @@ -96,7 +96,7 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); } - const ViewportEditorModeStateInterface* ViewportEditorModeStateTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + const ViewportEditorModesInterface* ViewportEditorModesTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const { if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); editorModeStates != m_viewportEditorModeStates.end()) @@ -109,12 +109,12 @@ namespace AzToolsFramework } } - size_t ViewportEditorModeStateTracker::GetNumTrackedViewports() const + size_t ViewportEditorModesTracker::GetNumTrackedViewports() const { return m_viewportEditorModeStates.size(); } - bool ViewportEditorModeStateTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + bool ViewportEditorModesTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const { return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h similarity index 68% rename from Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h index 30eabdf16e..4acd7f09b6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h @@ -11,14 +11,14 @@ #include #include #include -#include -#include +#include +#include namespace AzToolsFramework { //! The encapsulation of the editor modes for a given viewport. - class ViewportEditorModeState - : public ViewportEditorModeStateInterface + class ViewportEditorModes + : public ViewportEditorModesInterface { public: @@ -31,15 +31,15 @@ namespace AzToolsFramework // Sets the specified mode as inactive. void SetModeInactive(ViewportEditorMode mode); - // ViewportEditorModeStateInterface ... + // ViewportEditorModesInterface ... bool IsModeActive(ViewportEditorMode mode) const override; private: AZStd::array m_editorModes{}; //!< State flags to track active/inactive status of viewport editor modes. }; //! The implementation of the central editor mode state tracker for all viewports. - class ViewportEditorModeStateTracker - : public ViewportEditorModeStateTrackerInterface + class ViewportEditorModesTracker + : public ViewportEditorModesTrackerInterface { public: //! Registers this object with the AZ::Interface. @@ -48,15 +48,15 @@ namespace AzToolsFramework //! Unregisters this object with the AZ::Interface. void UnregisterInterface(); - // ViewportEditorModeStateTrackerInterface ... + // ViewportEditorModesTrackerInterface ... void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - const ViewportEditorModeStateInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetNumTrackedViewports() const override; bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: - using ViewportEditorModeStates = AZStd::unordered_map; - ViewportEditorModeStates m_viewportEditorModeStates; //!< Editor mode state per viewport. + using ViewportEditorModess = AZStd::unordered_map; + ViewportEditorModess m_viewportEditorModeStates; //!< Editor mode state per viewport. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 9b7394a6e7..65bc4e6b50 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -34,7 +34,7 @@ set(FILES API/EditorAnimationSystemRequestBus.h API/EditorEntityAPI.h API/EditorLevelNotificationBus.h - API/ViewportEditorModeStateTrackerNotificationBus.h + API/ViewportEditorModesTrackerNotificationBus.h API/EditorVegetationRequestsBus.h API/EditorPythonConsoleBus.h API/EditorPythonRunnerRequestsBus.h @@ -45,7 +45,7 @@ set(FILES API/EntityCompositionNotificationBus.h API/EditorViewportIconDisplayInterface.h API/ViewPaneOptions.h - API/ViewportEditorModeStateTrackerInterface.h + API/ViewportEditorModesTrackerInterface.h Application/Ticker.h Application/Ticker.cpp Application/EditorEntityManager.cpp @@ -540,8 +540,8 @@ set(FILES ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp ViewportSelection/EditorVisibleEntityDataCache.h ViewportSelection/EditorVisibleEntityDataCache.cpp - ViewportSelection/ViewportEditorModeStateTracker.cpp - ViewportSelection/ViewportEditorModeStateTracker.h + ViewportSelection/ViewportEditorModesTracker.cpp + ViewportSelection/ViewportEditorModesTracker.h ToolsFileUtils/ToolsFileUtils.h AssetBrowser/AssetBrowserBus.h AssetBrowser/AssetBrowserSourceDropBus.h diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index cae7092a8a..777fbe0585 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -8,44 +8,44 @@ #include #include -#include +#include namespace UnitTest { using ViewportEditorMode = AzToolsFramework::ViewportEditorMode; - using ViewportEditorModeState = AzToolsFramework::ViewportEditorModeState; - using ViewportEditorModeStateTracker = AzToolsFramework::ViewportEditorModeStateTracker; + using ViewportEditorModes = AzToolsFramework::ViewportEditorModes; + using ViewportEditorModesTracker = AzToolsFramework::ViewportEditorModesTracker; using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo; using ViewportId = ViewportEditorModeInfo::IdType; - using ViewportEditorModeStateInterface = AzToolsFramework::ViewportEditorModeStateInterface; + using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; - void SetAllModesActive(ViewportEditorModeState& editorModeState) + void SetAllModesActive(ViewportEditorModes& editorModeState) { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { editorModeState.SetModeActive(static_cast(mode)); } } - void SetAllModesInactive(ViewportEditorModeState& editorModeState) + void SetAllModesInactive(ViewportEditorModes& editorModeState) { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { editorModeState.SetModeInactive(static_cast(mode)); } } // Fixture for testing editor mode states - class ViewportEditorModeStateTestsFixture + class ViewportEditorModesTestsFixture : public ::testing::Test { public: - ViewportEditorModeState m_editorModeState; + ViewportEditorModes m_editorModeState; }; // Fixture for testing editor mode states with parameterized test arguments - class ViewportEditorModeStateTestsFixtureWithParams - : public ViewportEditorModeStateTestsFixture + class ViewportEditorModesTestsFixtureWithParams + : public ViewportEditorModesTestsFixture , public ::testing::WithParamInterface { public: @@ -58,11 +58,11 @@ namespace UnitTest }; // Fixture for testing the viewport editor mode state tracker - class ViewportEditorModeStateTrackerTestFixture + class ViewportEditorModesTrackerTestFixture : public ToolsApplicationFixture { public: - ViewportEditorModeStateTracker m_viewportEditorModeStteTracker; + ViewportEditorModesTracker m_viewportEditorModeStteTracker; }; // Subscriber of viewport editor mode notifications for a single viewport that expects a single mode to be activated/deactivated @@ -99,12 +99,12 @@ namespace UnitTest return m_editorModes; } - void OnEditorModeEnter([[maybe_unused]]const ViewportEditorModeStateInterface& editorModeState, ViewportEditorMode mode) override + void OnEditorModeEnter([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onEnter = true; } - virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, ViewportEditorMode mode) override + virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onLeave = true; } @@ -117,13 +117,13 @@ namespace UnitTest // Fixture for testing viewport editor mode notifications publishing class ViewportEditorModePublisherTestFixture - : public ViewportEditorModeStateTrackerTestFixture + : public ViewportEditorModesTrackerTestFixture { public: void SetUpEditorFixtureImpl() override { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { m_editorModeHandlers[mode] = AZStd::make_unique(mode); } @@ -131,33 +131,33 @@ namespace UnitTest void TearDownEditorFixtureImpl() override { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { m_editorModeHandlers[mode].reset(); } } - AZStd::array, ViewportEditorModeState::NumEditorModes> m_editorModeHandlers; + AZStd::array, ViewportEditorModes::NumEditorModes> m_editorModeHandlers; }; - TEST_F(ViewportEditorModeStateTestsFixture, NumberOfEditorModesIsEqualTo4) + TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4) { - EXPECT_EQ(ViewportEditorModeState::NumEditorModes, 4); + EXPECT_EQ(ViewportEditorModes::NumEditorModes, 4); } - TEST_F(ViewportEditorModeStateTestsFixture, InitialEditorModeStateHasAllInactiveModes) + TEST_F(ViewportEditorModesTestsFixture, InitialEditorModeStateHasAllInactiveModes) { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { EXPECT_FALSE(m_editorModeState.IsModeActive(static_cast(mode))); } } - TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) + TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { m_editorModeState.SetModeActive(m_selectedEditorMode); - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -171,12 +171,12 @@ namespace UnitTest } } - TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) + TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { SetAllModesActive(m_editorModeState); m_editorModeState.SetModeInactive(m_selectedEditorMode); - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -190,9 +190,9 @@ namespace UnitTest } } - TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively) + TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively) { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes - 1; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes - 1; mode++) { // Given only the selected mode active SetAllModesInactive(m_editorModeState); @@ -207,7 +207,7 @@ namespace UnitTest // When other modes are activated m_editorModeState.SetModeActive(editorMode); - for (auto expectedMode = 0; expectedMode < ViewportEditorModeState::NumEditorModes; expectedMode++) + for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { const auto expectedEditorMode = static_cast(expectedMode); if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) @@ -224,9 +224,9 @@ namespace UnitTest } } - TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingMultipleModesInactiveInactivatesAllThoseModesNonMutuallyExclusively) + TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesInactiveInactivatesAllThoseModesNonMutuallyExclusively) { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes - 1; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes - 1; mode++) { // Given only the selected mode inactive SetAllModesActive(m_editorModeState); @@ -241,7 +241,7 @@ namespace UnitTest // When other modes are deactivated m_editorModeState.SetModeInactive(editorMode); - for (auto expectedMode = 0; expectedMode < ViewportEditorModeState::NumEditorModes; expectedMode++) + for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { const auto expectedEditorMode = static_cast(expectedMode); if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) @@ -260,33 +260,33 @@ namespace UnitTest INSTANTIATE_TEST_CASE_P( AllEditorModes, - ViewportEditorModeStateTestsFixtureWithParams, + ViewportEditorModesTestsFixtureWithParams, ::testing::Values( AzToolsFramework::ViewportEditorMode::Default, AzToolsFramework::ViewportEditorMode::Component, AzToolsFramework::ViewportEditorMode::Focus, AzToolsFramework::ViewportEditorMode::Pick)); - TEST_F(ViewportEditorModeStateTestsFixture, SettingOutOfBoundsModeActiveIssuesErrorMsg) + TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveIssuesErrorMsg) { UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModeState.SetModeActive(static_cast(ViewportEditorModeState::NumEditorModes)); + m_editorModeState.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); } - TEST_F(ViewportEditorModeStateTestsFixture, SettingOutOfBoundsModeInactiveIssuesErrorMsg) + TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveIssuesErrorMsg) { UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModeState.SetModeInactive(static_cast(ViewportEditorModeState::NumEditorModes)); + m_editorModeState.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); } - TEST_F(ViewportEditorModeStateTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModeStates) + TEST_F(ViewportEditorModesTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) { EXPECT_EQ(m_viewportEditorModeStteTracker.GetNumTrackedViewports(), 0); } - TEST_F(ViewportEditorModeStateTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModeStateForThatId) + TEST_F(ViewportEditorModesTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -306,7 +306,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeStateTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModeStateForThatIdButIssuesErrorMsg) + TEST_F(ViewportEditorModesTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -331,14 +331,14 @@ namespace UnitTest EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeStateTrackerTestFixture, GettingNonExistentViewportEditorModeStateForIdReturnsNull) + TEST_F(ViewportEditorModesTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull) { const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); } - TEST_F(ViewportEditorModeStateTrackerTestFixture, EnteringViewportEditorModeStateForExistingIdInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModesTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -380,7 +380,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeStateTrackerTestFixture, ExitingViewportEditorModeStateForExistingIdNotInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModesTrackerTestFixture, ExitingViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -426,24 +426,24 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - EnteringViewportEditorModeStateForExistingIdPublishesOnViewportEditorModeEnterEventForAllSubscribers) + EnteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeEnterEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { // Expect each subscriber to have received no editor mode state changes EXPECT_EQ(m_editorModeHandlers[mode]->GetEditorModes().size(), 0); } // When each editor mode is activated by the state tracker for a specific viewport - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); m_viewportEditorModeStteTracker.EnterMode({ mode }, editorMode); } - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { // Expect only the subscribers of each viewport to have received the editor mode activated event const ViewportEditorMode editorMode = static_cast(mode); @@ -459,16 +459,16 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - ExitingViewportEditorModeStateForExistingIdPublishesOnViewportEditorModeExitEventForAllSubscribers) + ExitingViewportEditorModesForExistingIdPublishesOnViewportEditorModeExitEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { EXPECT_EQ(m_editorModeHandlers[mode]->GetEditorModes().size(), 0); } // When each editor mode is activated deactivated by the state tracker for a specific viewport - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); @@ -476,7 +476,7 @@ namespace UnitTest m_viewportEditorModeStteTracker.ExitMode({ mode }, editorMode); } - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { // Expect only the subscribers of each viewport to have received the editor mode activated and deactivated event const ViewportEditorMode editorMode = static_cast(mode); From 9553f4cc0f3d66578b85bc64d9dd12dfd541f51d Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 18:56:41 +0100 Subject: [PATCH 012/115] ViewportEditorModesTracker -> ViewportEditorModeTracker Signed-off-by: John --- ...ViewportEditorModeStateTrackerInterface.h} | 8 +- .../API/ViewportEditorModeTrackerInterface.h | 42 ++++++ ...iewportEditorModeTrackerNotificationBus.h} | 0 ...cpp => ViewportEditorModeStateTracker.cpp} | 26 ++-- ...ker.h => ViewportEditorModeStateTracker.h} | 10 +- .../ViewportEditorModeTracker.cpp | 121 ++++++++++++++++++ .../ViewportEditorModeTracker.h | 62 +++++++++ .../aztoolsframework_files.cmake | 8 +- .../Viewport/ViewportEditorModeTests.cpp | 22 ++-- 9 files changed, 262 insertions(+), 37 deletions(-) rename Code/Framework/AzToolsFramework/AzToolsFramework/API/{ViewportEditorModesTrackerInterface.h => ViewportEditorModeStateTrackerInterface.h} (83%) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h rename Code/Framework/AzToolsFramework/AzToolsFramework/API/{ViewportEditorModesTrackerNotificationBus.h => ViewportEditorModeTrackerNotificationBus.h} (100%) rename Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/{ViewportEditorModesTracker.cpp => ViewportEditorModeStateTracker.cpp} (76%) rename Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/{ViewportEditorModesTracker.h => ViewportEditorModeStateTracker.h} (88%) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h similarity index 83% rename from Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h index b13085bc83..09a39b1ec1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h @@ -9,17 +9,17 @@ #pragma once #include -#include +#include namespace AzToolsFramework { //! The AZ::Interface of the central editor mode state tracker for all viewports. - class ViewportEditorModesTrackerInterface + class ViewportEditorModeTrackerInterface { public: - AZ_RTTI(ViewportEditorModesTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); + AZ_RTTI(ViewportEditorModeTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); - virtual ~ViewportEditorModesTrackerInterface() = default; + virtual ~ViewportEditorModeTrackerInterface() = default; //! Enters the specified editor mode for the specified viewport. virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h new file mode 100644 index 0000000000..09a39b1ec1 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -0,0 +1,42 @@ +/* + * 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 + +namespace AzToolsFramework +{ + //! The AZ::Interface of the central editor mode state tracker for all viewports. + class ViewportEditorModeTrackerInterface + { + public: + AZ_RTTI(ViewportEditorModeTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); + + virtual ~ViewportEditorModeTrackerInterface() = default; + + //! Enters the specified editor mode for the specified viewport. + virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + + //! Exits the specified editor mode for the specified viewport. + virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + + //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. + virtual const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + + //! Returns the number of viewports currently being tracked. + virtual size_t GetNumTrackedViewports() const = 0; + + //! Returns true if the specified viewport is being tracked, otherwise false. + virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + + private: + }; +} // namespace AzToolsFramework + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h similarity index 100% rename from Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerNotificationBus.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp similarity index 76% rename from Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp rename to Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp index 5e6f73f963..5c9104ab18 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp @@ -6,8 +6,8 @@ * */ -#include -#include +#include +#include namespace AzToolsFramework { @@ -43,23 +43,23 @@ namespace AzToolsFramework return m_editorModes[static_cast(mode)]; } - void ViewportEditorModesTracker::RegisterInterface() + void ViewportEditorModeTracker::RegisterInterface() { - if (AZ::Interface::Get() == nullptr) + if (AZ::Interface::Get() == nullptr) { - AZ::Interface::Register(this); + AZ::Interface::Register(this); } } - void ViewportEditorModesTracker::UnregisterInterface() + void ViewportEditorModeTracker::UnregisterInterface() { - if (AZ::Interface::Get() != nullptr) + if (AZ::Interface::Get() != nullptr) { - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); } } - void ViewportEditorModesTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModeTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; AZ_Warning( @@ -71,7 +71,7 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); } - void ViewportEditorModesTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModeTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { ViewportEditorModes* editorModeStates = nullptr; if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) @@ -96,7 +96,7 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); } - const ViewportEditorModesInterface* ViewportEditorModesTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + const ViewportEditorModesInterface* ViewportEditorModeTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const { if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); editorModeStates != m_viewportEditorModeStates.end()) @@ -109,12 +109,12 @@ namespace AzToolsFramework } } - size_t ViewportEditorModesTracker::GetNumTrackedViewports() const + size_t ViewportEditorModeTracker::GetNumTrackedViewports() const { return m_viewportEditorModeStates.size(); } - bool ViewportEditorModesTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + bool ViewportEditorModeTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const { return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h similarity index 88% rename from Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h index 4acd7f09b6..23c02dbcdf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h @@ -11,8 +11,8 @@ #include #include #include -#include -#include +#include +#include namespace AzToolsFramework { @@ -38,8 +38,8 @@ namespace AzToolsFramework }; //! The implementation of the central editor mode state tracker for all viewports. - class ViewportEditorModesTracker - : public ViewportEditorModesTrackerInterface + class ViewportEditorModeTracker + : public ViewportEditorModeTrackerInterface { public: //! Registers this object with the AZ::Interface. @@ -48,7 +48,7 @@ namespace AzToolsFramework //! Unregisters this object with the AZ::Interface. void UnregisterInterface(); - // ViewportEditorModesTrackerInterface ... + // ViewportEditorModeTrackerInterface ... void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp new file mode 100644 index 0000000000..5c9104ab18 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -0,0 +1,121 @@ +/* + * 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 AzToolsFramework +{ + static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; + + void ViewportEditorModes::SetModeActive(ViewportEditorMode mode) + { + if (const AZ::u32 modeIndex = static_cast(mode); + modeIndex < NumEditorModes) + { + m_editorModes[modeIndex] = true; + } + else + { + AZ_Error(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex) + } + } + + void ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) + { + if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) + { + m_editorModes[modeIndex] = false; + } + else + { + AZ_Error(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex) + } + } + + bool ViewportEditorModes::IsModeActive(ViewportEditorMode mode) const + { + return m_editorModes[static_cast(mode)]; + } + + void ViewportEditorModeTracker::RegisterInterface() + { + if (AZ::Interface::Get() == nullptr) + { + AZ::Interface::Register(this); + } + } + + void ViewportEditorModeTracker::UnregisterInterface() + { + if (AZ::Interface::Get() != nullptr) + { + AZ::Interface::Unregister(this); + } + } + + void ViewportEditorModeTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + { + auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + AZ_Warning( + ViewportEditorModeLogWindow, !editorModeStates.IsModeActive(mode), + AZStd::string::format( + "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + editorModeStates.SetModeActive(mode); + ViewportEditorModeNotificationsBus::Event( + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); + } + + void ViewportEditorModeTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + { + ViewportEditorModes* editorModeStates = nullptr; + if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) + { + editorModeStates = &m_viewportEditorModeStates.at(viewportEditorModeInfo.m_id); + AZ_Warning( + ViewportEditorModeLogWindow, editorModeStates->IsModeActive(mode), + AZStd::string::format( + "Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + } + else + { + AZ_Warning( + ViewportEditorModeLogWindow, false, "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", + static_cast(mode), viewportEditorModeInfo.m_id); + + editorModeStates = &m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + } + + editorModeStates->SetModeInactive(mode); + ViewportEditorModeNotificationsBus::Event( + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); + } + + const ViewportEditorModesInterface* ViewportEditorModeTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + { + if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); + editorModeStates != m_viewportEditorModeStates.end()) + { + return &editorModeStates->second; + } + else + { + return nullptr; + } + } + + size_t ViewportEditorModeTracker::GetNumTrackedViewports() const + { + return m_viewportEditorModeStates.size(); + } + + bool ViewportEditorModeTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + { + return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; + } +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h new file mode 100644 index 0000000000..23c02dbcdf --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.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 +#include +#include +#include +#include + +namespace AzToolsFramework +{ + //! The encapsulation of the editor modes for a given viewport. + class ViewportEditorModes + : public ViewportEditorModesInterface + { + public: + + //! The number of currently supported viewport editor modes. + static constexpr AZ::u8 NumEditorModes = 4; + + //! Sets the specified mode as active. + void SetModeActive(ViewportEditorMode mode); + + // Sets the specified mode as inactive. + void SetModeInactive(ViewportEditorMode mode); + + // ViewportEditorModesInterface ... + bool IsModeActive(ViewportEditorMode mode) const override; + private: + AZStd::array m_editorModes{}; //!< State flags to track active/inactive status of viewport editor modes. + }; + + //! The implementation of the central editor mode state tracker for all viewports. + class ViewportEditorModeTracker + : public ViewportEditorModeTrackerInterface + { + public: + //! Registers this object with the AZ::Interface. + void RegisterInterface(); + + //! Unregisters this object with the AZ::Interface. + void UnregisterInterface(); + + // ViewportEditorModeTrackerInterface ... + void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + size_t GetNumTrackedViewports() const override; + bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + + private: + using ViewportEditorModess = AZStd::unordered_map; + ViewportEditorModess m_viewportEditorModeStates; //!< Editor mode state per viewport. + }; +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 65bc4e6b50..3932190d8e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -34,7 +34,7 @@ set(FILES API/EditorAnimationSystemRequestBus.h API/EditorEntityAPI.h API/EditorLevelNotificationBus.h - API/ViewportEditorModesTrackerNotificationBus.h + API/ViewportEditorModeTrackerNotificationBus.h API/EditorVegetationRequestsBus.h API/EditorPythonConsoleBus.h API/EditorPythonRunnerRequestsBus.h @@ -45,7 +45,7 @@ set(FILES API/EntityCompositionNotificationBus.h API/EditorViewportIconDisplayInterface.h API/ViewPaneOptions.h - API/ViewportEditorModesTrackerInterface.h + API/ViewportEditorModeTrackerInterface.h Application/Ticker.h Application/Ticker.cpp Application/EditorEntityManager.cpp @@ -540,8 +540,8 @@ set(FILES ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp ViewportSelection/EditorVisibleEntityDataCache.h ViewportSelection/EditorVisibleEntityDataCache.cpp - ViewportSelection/ViewportEditorModesTracker.cpp - ViewportSelection/ViewportEditorModesTracker.h + ViewportSelection/ViewportEditorModeTracker.cpp + ViewportSelection/ViewportEditorModeTracker.h ToolsFileUtils/ToolsFileUtils.h AssetBrowser/AssetBrowserBus.h AssetBrowser/AssetBrowserSourceDropBus.h diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 777fbe0585..63f975acdc 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -8,13 +8,13 @@ #include #include -#include +#include namespace UnitTest { using ViewportEditorMode = AzToolsFramework::ViewportEditorMode; using ViewportEditorModes = AzToolsFramework::ViewportEditorModes; - using ViewportEditorModesTracker = AzToolsFramework::ViewportEditorModesTracker; + using ViewportEditorModeTracker = AzToolsFramework::ViewportEditorModeTracker; using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo; using ViewportId = ViewportEditorModeInfo::IdType; using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; @@ -58,11 +58,11 @@ namespace UnitTest }; // Fixture for testing the viewport editor mode state tracker - class ViewportEditorModesTrackerTestFixture + class ViewportEditorModeTrackerTestFixture : public ToolsApplicationFixture { public: - ViewportEditorModesTracker m_viewportEditorModeStteTracker; + ViewportEditorModeTracker m_viewportEditorModeStteTracker; }; // Subscriber of viewport editor mode notifications for a single viewport that expects a single mode to be activated/deactivated @@ -117,7 +117,7 @@ namespace UnitTest // Fixture for testing viewport editor mode notifications publishing class ViewportEditorModePublisherTestFixture - : public ViewportEditorModesTrackerTestFixture + : public ViewportEditorModeTrackerTestFixture { public: @@ -281,12 +281,12 @@ namespace UnitTest EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); } - TEST_F(ViewportEditorModesTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) + TEST_F(ViewportEditorModeTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) { EXPECT_EQ(m_viewportEditorModeStteTracker.GetNumTrackedViewports(), 0); } - TEST_F(ViewportEditorModesTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) + TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -306,7 +306,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModesTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -331,14 +331,14 @@ namespace UnitTest EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModesTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull) + TEST_F(ViewportEditorModeTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull) { const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); } - TEST_F(ViewportEditorModesTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -380,7 +380,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModesTrackerTestFixture, ExitingViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, ExitingViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; From 35a228b08f988bc219a67fc78f63253e69a65984 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 18:57:36 +0100 Subject: [PATCH 013/115] GetEditorModeState ->GetViewportEditorModes Signed-off-by: John --- .../ViewportEditorModeStateTrackerInterface.h | 2 +- .../API/ViewportEditorModeTrackerInterface.h | 2 +- .../ViewportEditorModeStateTracker.cpp | 2 +- .../ViewportEditorModeStateTracker.h | 2 +- .../ViewportEditorModeTracker.cpp | 2 +- .../ViewportEditorModeTracker.h | 2 +- .../Viewport/ViewportEditorModeTests.cpp | 22 +++++++++---------- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h index 09a39b1ec1..706fd98c5e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h @@ -28,7 +28,7 @@ namespace AzToolsFramework virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. - virtual const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; //! Returns the number of viewports currently being tracked. virtual size_t GetNumTrackedViewports() const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 09a39b1ec1..706fd98c5e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -28,7 +28,7 @@ namespace AzToolsFramework virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. - virtual const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; //! Returns the number of viewports currently being tracked. virtual size_t GetNumTrackedViewports() const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp index 5c9104ab18..e78f564c9d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp @@ -96,7 +96,7 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); } - const ViewportEditorModesInterface* ViewportEditorModeTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const { if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); editorModeStates != m_viewportEditorModeStates.end()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h index 23c02dbcdf..be090e6f1f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h @@ -51,7 +51,7 @@ namespace AzToolsFramework // ViewportEditorModeTrackerInterface ... void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetNumTrackedViewports() const override; bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 5c9104ab18..e78f564c9d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -96,7 +96,7 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); } - const ViewportEditorModesInterface* ViewportEditorModeTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const { if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); editorModeStates != m_viewportEditorModeStates.end()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 23c02dbcdf..be090e6f1f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -51,7 +51,7 @@ namespace AzToolsFramework // ViewportEditorModeTrackerInterface ... void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetNumTrackedViewports() const override; bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 63f975acdc..d59e017579 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -291,12 +291,12 @@ namespace UnitTest // Given a viewport not currently being tracked const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is activated for that viewport const auto editorMode = ViewportEditorMode::Default; m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); // Expect that viewport to now be tracked EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); @@ -311,7 +311,7 @@ namespace UnitTest // Given a viewport not currently being tracked const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is deactivated for that viewport const auto editorMode = ViewportEditorMode::Default; @@ -323,7 +323,7 @@ namespace UnitTest EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect that viewport to now be tracked - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); // Expect the mode for that viewport to be inactive @@ -335,7 +335,7 @@ namespace UnitTest { const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); } TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) @@ -343,7 +343,7 @@ namespace UnitTest // Given a viewport not currently tracked const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = AZStd::string::format( @@ -359,7 +359,7 @@ namespace UnitTest EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); // Expect the mode to be active for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); @@ -373,7 +373,7 @@ namespace UnitTest EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect the mode to still be active for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); @@ -385,7 +385,7 @@ namespace UnitTest // Given a viewport not currently tracked const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = @@ -402,7 +402,7 @@ namespace UnitTest EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); // Expect the mode to be inctive for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); @@ -417,7 +417,7 @@ namespace UnitTest EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect the mode to still be inactive for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); From 3b47d9c5a659972759b3147ab38e313489ba14a9 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 19:15:18 +0100 Subject: [PATCH 014/115] GetNumTrackedViewports -> GetTrackedViewportCount Signed-off-by: John --- .../API/ViewportEditorModeStateTrackerInterface.h | 2 +- .../AzToolsFramework/API/ViewportEditorModeTrackerInterface.h | 2 +- .../ViewportSelection/ViewportEditorModeStateTracker.cpp | 2 +- .../ViewportSelection/ViewportEditorModeStateTracker.h | 2 +- .../ViewportSelection/ViewportEditorModeTracker.cpp | 2 +- .../ViewportSelection/ViewportEditorModeTracker.h | 2 +- .../AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h index 706fd98c5e..7d51dd64a1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h @@ -31,7 +31,7 @@ namespace AzToolsFramework virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; //! Returns the number of viewports currently being tracked. - virtual size_t GetNumTrackedViewports() const = 0; + virtual size_t GetTrackedViewportCount() const = 0; //! Returns true if the specified viewport is being tracked, otherwise false. virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 706fd98c5e..7d51dd64a1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -31,7 +31,7 @@ namespace AzToolsFramework virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; //! Returns the number of viewports currently being tracked. - virtual size_t GetNumTrackedViewports() const = 0; + virtual size_t GetTrackedViewportCount() const = 0; //! Returns true if the specified viewport is being tracked, otherwise false. virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp index e78f564c9d..3d88d7d93e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp @@ -109,7 +109,7 @@ namespace AzToolsFramework } } - size_t ViewportEditorModeTracker::GetNumTrackedViewports() const + size_t ViewportEditorModeTracker::GetTrackedViewportCount() const { return m_viewportEditorModeStates.size(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h index be090e6f1f..12a64cbbf9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h @@ -52,7 +52,7 @@ namespace AzToolsFramework void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; - size_t GetNumTrackedViewports() const override; + size_t GetTrackedViewportCount() const override; bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index e78f564c9d..3d88d7d93e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -109,7 +109,7 @@ namespace AzToolsFramework } } - size_t ViewportEditorModeTracker::GetNumTrackedViewports() const + size_t ViewportEditorModeTracker::GetTrackedViewportCount() const { return m_viewportEditorModeStates.size(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index be090e6f1f..12a64cbbf9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -52,7 +52,7 @@ namespace AzToolsFramework void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; - size_t GetNumTrackedViewports() const override; + size_t GetTrackedViewportCount() const override; bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index d59e017579..8e9b1ba59b 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -283,7 +283,7 @@ namespace UnitTest TEST_F(ViewportEditorModeTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) { - EXPECT_EQ(m_viewportEditorModeStteTracker.GetNumTrackedViewports(), 0); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetTrackedViewportCount(), 0); } TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) From 7960c68b487622f0e99ed8f0f7d72699276d85b5 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 19:16:22 +0100 Subject: [PATCH 015/115] IsViewportStateBeingTracked -> IsViewportModeTracked Signed-off-by: John --- .../ViewportEditorModeStateTrackerInterface.h | 2 +- .../API/ViewportEditorModeTrackerInterface.h | 2 +- .../ViewportEditorModeStateTracker.cpp | 2 +- .../ViewportEditorModeStateTracker.h | 2 +- .../ViewportEditorModeTracker.cpp | 2 +- .../ViewportEditorModeTracker.h | 2 +- .../Viewport/ViewportEditorModeTests.cpp | 22 +++++++++---------- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h index 7d51dd64a1..53b0729bac 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h @@ -34,7 +34,7 @@ namespace AzToolsFramework virtual size_t GetTrackedViewportCount() const = 0; //! Returns true if the specified viewport is being tracked, otherwise false. - virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + virtual bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; private: }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 7d51dd64a1..53b0729bac 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -34,7 +34,7 @@ namespace AzToolsFramework virtual size_t GetTrackedViewportCount() const = 0; //! Returns true if the specified viewport is being tracked, otherwise false. - virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + virtual bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; private: }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp index 3d88d7d93e..2eb8cdb9d8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp @@ -114,7 +114,7 @@ namespace AzToolsFramework return m_viewportEditorModeStates.size(); } - bool ViewportEditorModeTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const { return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h index 12a64cbbf9..0ec5a31ddd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h @@ -53,7 +53,7 @@ namespace AzToolsFramework void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetTrackedViewportCount() const override; - bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: using ViewportEditorModess = AZStd::unordered_map; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 3d88d7d93e..2eb8cdb9d8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -114,7 +114,7 @@ namespace AzToolsFramework return m_viewportEditorModeStates.size(); } - bool ViewportEditorModeTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const { return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 12a64cbbf9..0ec5a31ddd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -53,7 +53,7 @@ namespace AzToolsFramework void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetTrackedViewportCount() const override; - bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: using ViewportEditorModess = AZStd::unordered_map; diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 8e9b1ba59b..7603f68b64 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -290,7 +290,7 @@ namespace UnitTest { // Given a viewport not currently being tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is activated for that viewport @@ -299,7 +299,7 @@ namespace UnitTest const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); // Expect that viewport to now be tracked - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); // Expect the mode for that viewport to be active @@ -310,7 +310,7 @@ namespace UnitTest { // Given a viewport not currently being tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is deactivated for that viewport @@ -324,7 +324,7 @@ namespace UnitTest // Expect that viewport to now be tracked const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); // Expect the mode for that viewport to be inactive EXPECT_NE(viewportEditorModeState, nullptr); @@ -334,7 +334,7 @@ namespace UnitTest TEST_F(ViewportEditorModeTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull) { const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); } @@ -342,7 +342,7 @@ namespace UnitTest { // Given a viewport not currently tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; @@ -360,7 +360,7 @@ namespace UnitTest // Expect the mode to be active for the viewport const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -374,7 +374,7 @@ namespace UnitTest // Expect the mode to still be active for the viewport const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -384,7 +384,7 @@ namespace UnitTest { // Given a viewport not currently tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; @@ -403,7 +403,7 @@ namespace UnitTest // Expect the mode to be inctive for the viewport const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -418,7 +418,7 @@ namespace UnitTest // Expect the mode to still be inactive for the viewport const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } From 9dfc91cb77ad66c7a3c79135d7f8d43cd3d11330 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 19:26:50 +0100 Subject: [PATCH 016/115] Fix API comments. Signed-off-by: John --- ...ViewportEditorModeTrackerNotificationBus.h | 5 +-- .../EditorInteractionInterface.h | 33 ------------------- 2 files changed, 3 insertions(+), 35 deletions(-) delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index b9b5c80f39..cdb50e30e7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include @@ -13,7 +14,7 @@ namespace AzToolsFramework { - //! Enumeration of each viewport editor state. + //! Enumeration of each viewport editor mode. enum class ViewportEditorMode : AZ::u8 { Default, @@ -62,4 +63,4 @@ namespace AzToolsFramework } }; using ViewportEditorModeNotificationsBus = AZ::EBus; -} +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h deleted file mode 100644 index 70cbfd09ec..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h +++ /dev/null @@ -1,33 +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 - -namespace AzToolsFramework -{ - /*! - * EditorInteractionInterface - * Allows systems to alter the behavior of viewport selection. - */ - class EditorInteractionInterface - { - public: - AZ_RTTI(EditorInteractionInterface, "{09276E3C-9AA6-40FF-A0B5-3D33A33F0E5A}"); - - /*! - * Allows the entity system to redirect the selection of an entity to another entity. - * It can be used to select a container when clicking on its content. - */ - virtual AZ::EntityId RedirectEntitySelection(AZ::EntityId entityId) = 0; - }; - -} // namespace AzToolsFramework - From 860571f1e33c985b7a2e86618c61f5f86e7abd36 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Tue, 14 Sep 2021 18:45:22 -0700 Subject: [PATCH 017/115] WIP trying to get android package working. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Common/Code/Source/Platform/Windows/platform_windows.cmake | 1 - Gems/Atom/Utils/Code/Platform/Windows/platform_windows.cmake | 1 - cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake | 2 +- cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake b/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake index ef84846c0f..7c594fc945 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake +++ b/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake @@ -13,5 +13,4 @@ endif() set(LY_BUILD_DEPENDENCIES PRIVATE 3rdParty::ilmbase - 3rdParty::libpng ) diff --git a/Gems/Atom/Utils/Code/Platform/Windows/platform_windows.cmake b/Gems/Atom/Utils/Code/Platform/Windows/platform_windows.cmake index ead5aa05de..c1d40c6ad8 100644 --- a/Gems/Atom/Utils/Code/Platform/Windows/platform_windows.cmake +++ b/Gems/Atom/Utils/Code/Platform/Windows/platform_windows.cmake @@ -9,5 +9,4 @@ set(LY_BUILD_DEPENDENCIES PRIVATE 3rdParty::OpenImageIO - 3rdParty::libpng ) diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index 4858b85670..e9160a329d 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -24,7 +24,7 @@ ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-android TARGETS Phy ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-android TARGETS mikkelsen PACKAGE_HASH 075e8e4940884971063b5a9963014e2e517246fa269c07c7dc55b8cf2cd99705) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-android TARGETS googletest PACKAGE_HASH 95671be75287a61c9533452835c3647e9c1b30f81b34b43bcb0ec1997cc23894) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-android TARGETS GoogleBenchmark PACKAGE_HASH 20b46e572211a69d7d94ddad1c89ec37bb958711d6ad4025368ac89ea83078fb) -ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 0000000000000000000000000000000000000000000000000000000000000000) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-android TARGETS libpng PACKAGE_HASH d6adef1d1a90e0163ae2ab82dcc3f23f38b81438d0d8d4c6d219d600881e807e) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-android TARGETS libsamplerate PACKAGE_HASH bf13662afe65d02bcfa16258a4caa9b875534978227d6f9f36c9cfa92b3fb12b) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-android TARGETS OpenSSL PACKAGE_HASH 4036d4019d722f0e1b7a1621bf60b5a17ca6a65c9c78fd8701cee1131eec8480) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-android TARGETS zlib PACKAGE_HASH 85b730b97176772538cfcacd6b6aaf4655fc2d368d134d6dd55e02f28f183826) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 44af91620f..d1bfcfb031 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -37,7 +37,7 @@ ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-linux ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-linux TARGETS GoogleBenchmark PACKAGE_HASH 4038878f337fc7e0274f0230f71851b385b2e0327c495fc3dd3d1c18a807928d) ly_associate_package(PACKAGE_NAME unwind-1.2.1-linux TARGETS unwind PACKAGE_HASH 3453265fb056e25432f611a61546a25f60388e315515ad39007b5925dd054a77) ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-linux TARGETS Qt PACKAGE_HASH 76b395897b941a173002845c7219a5f8a799e44b269ffefe8091acc048130f28) -ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 0000000000000000000000000000000000000000000000000000000000000000) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-linux TARGETS libpng PACKAGE_HASH 0000000000000000000000000000000000000000000000000000000000000000) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-linux TARGETS libsamplerate PACKAGE_HASH 41643c31bc6b7d037f895f89d8d8d6369e906b92eff42b0fe05ee6a100f06261) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-linux TARGETS OpenSSL PACKAGE_HASH b779426d1e9c5ddf71160d5ae2e639c3b956e0fb5e9fcaf9ce97c4526024e3bc) ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-linux TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 88c4a359325d749bc34090b9ac466424847f3b71ba0de15045cf355c17c07099) From bcef5e4952d76c3b0646f8fccb3bced345a1fb6d Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Tue, 14 Sep 2021 22:09:46 -0700 Subject: [PATCH 018/115] I think I got the libpng android package working. Note there is a bit of a dependency hack in Gems\Atom\Feature\Common\Code\CMakeLists.txt to work around a mysterious issue; I'll reach out to some experts for investigation. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- Gems/Atom/Feature/Common/Code/CMakeLists.txt | 7 +++++++ Gems/Atom/Utils/Code/CMakeLists.txt | 1 + .../Platform/Android/BuiltInPackages_android.cmake | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/CMakeLists.txt b/Gems/Atom/Feature/Common/Code/CMakeLists.txt index b8c414dcc6..3a38aefe02 100644 --- a/Gems/Atom/Feature/Common/Code/CMakeLists.txt +++ b/Gems/Atom/Feature/Common/Code/CMakeLists.txt @@ -83,6 +83,13 @@ ly_add_target( Include BUILD_DEPENDENCIES PRIVATE + # For some reason zlib and libpng need to be declared here, otherwise libAtom_Feature_Common.so will fail to link + # when building for Android. These libraries are appropriately indicated in Atom/Utils's CCmakeLists.txt and those dependencies are + # supposed to be inherited here through the PUBLIC dependencies chaining ... but something is amiss. libpng and zlib were both + # appearing in the link command so it isn't clear why it was failing. Perhaps it was because libpng appeared before zlib + # in the link command? Somehow repeating them here works around this issue. + 3rdParty::libpng + 3rdParty::zlib AZ::AzCore AZ::AzFramework Gem::Atom_Feature_Common.Static diff --git a/Gems/Atom/Utils/Code/CMakeLists.txt b/Gems/Atom/Utils/Code/CMakeLists.txt index 89bc8dd0a5..0781100e9a 100644 --- a/Gems/Atom/Utils/Code/CMakeLists.txt +++ b/Gems/Atom/Utils/Code/CMakeLists.txt @@ -24,6 +24,7 @@ ly_add_target( Gem::Atom_RHI.Public PUBLIC Gem::Atom_RHI.Reflect + 3rdParty::zlib 3rdParty::libpng ) diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index e9160a329d..333b9a5444 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -24,7 +24,7 @@ ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-android TARGETS Phy ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-android TARGETS mikkelsen PACKAGE_HASH 075e8e4940884971063b5a9963014e2e517246fa269c07c7dc55b8cf2cd99705) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-android TARGETS googletest PACKAGE_HASH 95671be75287a61c9533452835c3647e9c1b30f81b34b43bcb0ec1997cc23894) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-android TARGETS GoogleBenchmark PACKAGE_HASH 20b46e572211a69d7d94ddad1c89ec37bb958711d6ad4025368ac89ea83078fb) -ly_associate_package(PACKAGE_NAME libpng-1.6.37-android TARGETS libpng PACKAGE_HASH d6adef1d1a90e0163ae2ab82dcc3f23f38b81438d0d8d4c6d219d600881e807e) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-android TARGETS libpng PACKAGE_HASH 72be3859de38559ed45e4383bc480ad9cc1c080fea2c4d6dd3946c2fb22ad5bb) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-android TARGETS libsamplerate PACKAGE_HASH bf13662afe65d02bcfa16258a4caa9b875534978227d6f9f36c9cfa92b3fb12b) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-android TARGETS OpenSSL PACKAGE_HASH 4036d4019d722f0e1b7a1621bf60b5a17ca6a65c9c78fd8701cee1131eec8480) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-android TARGETS zlib PACKAGE_HASH 85b730b97176772538cfcacd6b6aaf4655fc2d368d134d6dd55e02f28f183826) From 82fbbb79664be8a4054d0d48752e20ab34f866eb Mon Sep 17 00:00:00 2001 From: John Date: Wed, 15 Sep 2021 08:53:59 +0100 Subject: [PATCH 019/115] Delete hangover file. Signed-off-by: John --- .../ViewportEditorModeStateTrackerInterface.h | 42 ------------------- 1 file changed, 42 deletions(-) delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h deleted file mode 100644 index 53b0729bac..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h +++ /dev/null @@ -1,42 +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 - -namespace AzToolsFramework -{ - //! The AZ::Interface of the central editor mode state tracker for all viewports. - class ViewportEditorModeTrackerInterface - { - public: - AZ_RTTI(ViewportEditorModeTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); - - virtual ~ViewportEditorModeTrackerInterface() = default; - - //! Enters the specified editor mode for the specified viewport. - virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; - - //! Exits the specified editor mode for the specified viewport. - virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; - - //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. - virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; - - //! Returns the number of viewports currently being tracked. - virtual size_t GetTrackedViewportCount() const = 0; - - //! Returns true if the specified viewport is being tracked, otherwise false. - virtual bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; - - private: - }; -} // namespace AzToolsFramework - From 00497ad9959694ee48c6dfdb6ace16da3cd2bdad Mon Sep 17 00:00:00 2001 From: John Date: Wed, 15 Sep 2021 09:05:56 +0100 Subject: [PATCH 020/115] Delete more hangover files. Signed-off-by: John --- .../ViewportEditorModeStateTracker.cpp | 121 ------------------ .../ViewportEditorModeStateTracker.h | 62 --------- 2 files changed, 183 deletions(-) delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp deleted file mode 100644 index 2eb8cdb9d8..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp +++ /dev/null @@ -1,121 +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 - -namespace AzToolsFramework -{ - static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; - - void ViewportEditorModes::SetModeActive(ViewportEditorMode mode) - { - if (const AZ::u32 modeIndex = static_cast(mode); - modeIndex < NumEditorModes) - { - m_editorModes[modeIndex] = true; - } - else - { - AZ_Error(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex) - } - } - - void ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) - { - if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) - { - m_editorModes[modeIndex] = false; - } - else - { - AZ_Error(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex) - } - } - - bool ViewportEditorModes::IsModeActive(ViewportEditorMode mode) const - { - return m_editorModes[static_cast(mode)]; - } - - void ViewportEditorModeTracker::RegisterInterface() - { - if (AZ::Interface::Get() == nullptr) - { - AZ::Interface::Register(this); - } - } - - void ViewportEditorModeTracker::UnregisterInterface() - { - if (AZ::Interface::Get() != nullptr) - { - AZ::Interface::Unregister(this); - } - } - - void ViewportEditorModeTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) - { - auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; - AZ_Warning( - ViewportEditorModeLogWindow, !editorModeStates.IsModeActive(mode), - AZStd::string::format( - "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); - editorModeStates.SetModeActive(mode); - ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); - } - - void ViewportEditorModeTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) - { - ViewportEditorModes* editorModeStates = nullptr; - if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) - { - editorModeStates = &m_viewportEditorModeStates.at(viewportEditorModeInfo.m_id); - AZ_Warning( - ViewportEditorModeLogWindow, editorModeStates->IsModeActive(mode), - AZStd::string::format( - "Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); - } - else - { - AZ_Warning( - ViewportEditorModeLogWindow, false, "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", - static_cast(mode), viewportEditorModeInfo.m_id); - - editorModeStates = &m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; - } - - editorModeStates->SetModeInactive(mode); - ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); - } - - const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const - { - if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); - editorModeStates != m_viewportEditorModeStates.end()) - { - return &editorModeStates->second; - } - else - { - return nullptr; - } - } - - size_t ViewportEditorModeTracker::GetTrackedViewportCount() const - { - return m_viewportEditorModeStates.size(); - } - - bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const - { - return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; - } -} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h deleted file mode 100644 index 0ec5a31ddd..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h +++ /dev/null @@ -1,62 +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 - -namespace AzToolsFramework -{ - //! The encapsulation of the editor modes for a given viewport. - class ViewportEditorModes - : public ViewportEditorModesInterface - { - public: - - //! The number of currently supported viewport editor modes. - static constexpr AZ::u8 NumEditorModes = 4; - - //! Sets the specified mode as active. - void SetModeActive(ViewportEditorMode mode); - - // Sets the specified mode as inactive. - void SetModeInactive(ViewportEditorMode mode); - - // ViewportEditorModesInterface ... - bool IsModeActive(ViewportEditorMode mode) const override; - private: - AZStd::array m_editorModes{}; //!< State flags to track active/inactive status of viewport editor modes. - }; - - //! The implementation of the central editor mode state tracker for all viewports. - class ViewportEditorModeTracker - : public ViewportEditorModeTrackerInterface - { - public: - //! Registers this object with the AZ::Interface. - void RegisterInterface(); - - //! Unregisters this object with the AZ::Interface. - void UnregisterInterface(); - - // ViewportEditorModeTrackerInterface ... - void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; - size_t GetTrackedViewportCount() const override; - bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; - - private: - using ViewportEditorModess = AZStd::unordered_map; - ViewportEditorModess m_viewportEditorModeStates; //!< Editor mode state per viewport. - }; -} // namespace AzToolsFramework From 66f78889e656a2569a3d3c36663bb2714f2faeec Mon Sep 17 00:00:00 2001 From: John Date: Wed, 15 Sep 2021 09:26:16 +0100 Subject: [PATCH 021/115] Minor member name refactor. Signed-off-by: John --- .../Viewport/ViewportEditorModeTests.cpp | 110 +++++++++--------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 7603f68b64..7eb4f68d87 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -40,7 +40,7 @@ namespace UnitTest : public ::testing::Test { public: - ViewportEditorModes m_editorModeState; + ViewportEditorModes m_editorModes; }; // Fixture for testing editor mode states with parameterized test arguments @@ -62,7 +62,7 @@ namespace UnitTest : public ToolsApplicationFixture { public: - ViewportEditorModeTracker m_viewportEditorModeStteTracker; + ViewportEditorModeTracker m_viewportEditorModeTracker; }; // Subscriber of viewport editor mode notifications for a single viewport that expects a single mode to be activated/deactivated @@ -149,43 +149,43 @@ namespace UnitTest { for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { - EXPECT_FALSE(m_editorModeState.IsModeActive(static_cast(mode))); + EXPECT_FALSE(m_editorModes.IsModeActive(static_cast(mode))); } } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { - m_editorModeState.SetModeActive(m_selectedEditorMode); + m_editorModes.SetModeActive(m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) { - EXPECT_TRUE(m_editorModeState.IsModeActive(static_cast(editorMode))); + EXPECT_TRUE(m_editorModes.IsModeActive(static_cast(editorMode))); } else { - EXPECT_FALSE(m_editorModeState.IsModeActive(static_cast(editorMode))); + EXPECT_FALSE(m_editorModes.IsModeActive(static_cast(editorMode))); } } } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { - SetAllModesActive(m_editorModeState); - m_editorModeState.SetModeInactive(m_selectedEditorMode); + SetAllModesActive(m_editorModes); + m_editorModes.SetModeInactive(m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) { - EXPECT_FALSE(m_editorModeState.IsModeActive(editorMode)); + EXPECT_FALSE(m_editorModes.IsModeActive(editorMode)); } else { - EXPECT_TRUE(m_editorModeState.IsModeActive(editorMode)); + EXPECT_TRUE(m_editorModes.IsModeActive(editorMode)); } } } @@ -195,8 +195,8 @@ namespace UnitTest for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes - 1; mode++) { // Given only the selected mode active - SetAllModesInactive(m_editorModeState); - m_editorModeState.SetModeActive(m_selectedEditorMode); + SetAllModesInactive(m_editorModes); + m_editorModes.SetModeActive(m_selectedEditorMode); const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -205,7 +205,7 @@ namespace UnitTest } // When other modes are activated - m_editorModeState.SetModeActive(editorMode); + m_editorModes.SetModeActive(editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -213,12 +213,12 @@ namespace UnitTest if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) { // Expect the activated modes to be active - EXPECT_TRUE(m_editorModeState.IsModeActive(expectedEditorMode)); + EXPECT_TRUE(m_editorModes.IsModeActive(expectedEditorMode)); } else { // Expect the modes not active to be inactive - EXPECT_FALSE(m_editorModeState.IsModeActive(expectedEditorMode)); + EXPECT_FALSE(m_editorModes.IsModeActive(expectedEditorMode)); } } } @@ -229,8 +229,8 @@ namespace UnitTest for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes - 1; mode++) { // Given only the selected mode inactive - SetAllModesActive(m_editorModeState); - m_editorModeState.SetModeInactive(m_selectedEditorMode); + SetAllModesActive(m_editorModes); + m_editorModes.SetModeInactive(m_selectedEditorMode); const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -239,7 +239,7 @@ namespace UnitTest } // When other modes are deactivated - m_editorModeState.SetModeInactive(editorMode); + m_editorModes.SetModeInactive(editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -247,12 +247,12 @@ namespace UnitTest if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) { // Expect the deactivated modes to be inactive - EXPECT_FALSE(m_editorModeState.IsModeActive(expectedEditorMode)); + EXPECT_FALSE(m_editorModes.IsModeActive(expectedEditorMode)); } else { // Expects the modes not deactivated to still be active - EXPECT_TRUE(m_editorModeState.IsModeActive(expectedEditorMode)); + EXPECT_TRUE(m_editorModes.IsModeActive(expectedEditorMode)); } } } @@ -270,36 +270,36 @@ namespace UnitTest TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveIssuesErrorMsg) { UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModeState.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); + m_editorModes.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); } TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveIssuesErrorMsg) { UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModeState.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); + m_editorModes.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); } TEST_F(ViewportEditorModeTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) { - EXPECT_EQ(m_viewportEditorModeStteTracker.GetTrackedViewportCount(), 0); + EXPECT_EQ(m_viewportEditorModeTracker.GetTrackedViewportCount(), 0); } TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); + EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is activated for that viewport const auto editorMode = ViewportEditorMode::Default; - m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); + m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); // Expect that viewport to now be tracked - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); // Expect the mode for that viewport to be active @@ -310,21 +310,21 @@ namespace UnitTest { // Given a viewport not currently being tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); + EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is deactivated for that viewport const auto editorMode = ViewportEditorMode::Default; UnitTest::ErrorHandler errorHandler(AZStd::string::format( "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", static_cast(editorMode), viewportid).c_str()); - m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); // Expect a warning to be issued due to no precursor activation of that mode EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect that viewport to now be tracked - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); // Expect the mode for that viewport to be inactive EXPECT_NE(viewportEditorModeState, nullptr); @@ -334,16 +334,16 @@ namespace UnitTest TEST_F(ViewportEditorModeTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull) { const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); + EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); } TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); + EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = AZStd::string::format( @@ -353,28 +353,28 @@ namespace UnitTest UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is activated for the viewport - m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); // Expect no warning to be issued as there is no duplicate activation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); // Expect the mode to be active for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } { // When the mode is activated again for the viewport UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); // Expect a warning to be issued for the duplicate activation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect the mode to still be active for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -384,8 +384,8 @@ namespace UnitTest { // Given a viewport not currently tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); + EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = @@ -395,15 +395,15 @@ namespace UnitTest UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is activated and then deactivated for the viewport - m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); - m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); // Expect no warning to be issued as there is no duplicate deactivation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); // Expect the mode to be inctive for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -411,14 +411,14 @@ namespace UnitTest UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is deactivated again for the viewport - m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); // Expect a warning to be issued for the duplicate deactivation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect the mode to still be inactive for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -440,7 +440,7 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeStteTracker.EnterMode({ mode }, editorMode); + m_viewportEditorModeTracker.EnterMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -472,8 +472,8 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeStteTracker.EnterMode({ mode }, editorMode); - m_viewportEditorModeStteTracker.ExitMode({ mode }, editorMode); + m_viewportEditorModeTracker.EnterMode({ mode }, editorMode); + m_viewportEditorModeTracker.ExitMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) From 15ae8c2c064d6f43c3a1da7877e4973ebef4bbb9 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 15 Sep 2021 11:00:59 +0100 Subject: [PATCH 022/115] Refactor nonclemanture. Signed-off-by: John --- .../API/ViewportEditorModeTrackerInterface.h | 4 +-- ...ViewportEditorModeTrackerNotificationBus.h | 2 +- .../ViewportEditorModeTracker.cpp | 32 +++++++++---------- .../ViewportEditorModeTracker.h | 4 +-- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 53b0729bac..4bafdc3d01 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -13,7 +13,7 @@ namespace AzToolsFramework { - //! The AZ::Interface of the central editor mode state tracker for all viewports. + //! The AZ::Interface of the central editor mode tracker for all viewports. class ViewportEditorModeTrackerInterface { public: @@ -35,8 +35,6 @@ namespace AzToolsFramework //! Returns true if the specified viewport is being tracked, otherwise false. virtual bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; - - private: }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index cdb50e30e7..caa762241c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -30,7 +30,7 @@ namespace AzToolsFramework IdType m_id = ViewportUi::DefaultViewportId; //!< The unique identifier for a given viewport. }; - //! Interface for the editor mode state of a given viewport. + //! Interface for the editor modes of a given viewport. class ViewportEditorModesInterface { public: diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 2eb8cdb9d8..511024daed 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -61,24 +61,24 @@ namespace AzToolsFramework void ViewportEditorModeTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { - auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + auto& editorModes = m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; AZ_Warning( - ViewportEditorModeLogWindow, !editorModeStates.IsModeActive(mode), + ViewportEditorModeLogWindow, !editorModes.IsModeActive(mode), AZStd::string::format( "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); - editorModeStates.SetModeActive(mode); + editorModes.SetModeActive(mode); ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModes, mode); } void ViewportEditorModeTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { - ViewportEditorModes* editorModeStates = nullptr; - if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) + ViewportEditorModes* editorModes = nullptr; + if (m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id)) { - editorModeStates = &m_viewportEditorModeStates.at(viewportEditorModeInfo.m_id); + editorModes = &m_viewportEditorModesMap.at(viewportEditorModeInfo.m_id); AZ_Warning( - ViewportEditorModeLogWindow, editorModeStates->IsModeActive(mode), + ViewportEditorModeLogWindow, editorModes->IsModeActive(mode), AZStd::string::format( "Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); } @@ -88,20 +88,20 @@ namespace AzToolsFramework ViewportEditorModeLogWindow, false, "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", static_cast(mode), viewportEditorModeInfo.m_id); - editorModeStates = &m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + editorModes = &m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; } - editorModeStates->SetModeInactive(mode); + editorModes->SetModeInactive(mode); ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModes, mode); } const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const { - if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); - editorModeStates != m_viewportEditorModeStates.end()) + if (auto editorModes = m_viewportEditorModesMap.find(viewportEditorModeInfo.m_id); + editorModes != m_viewportEditorModesMap.end()) { - return &editorModeStates->second; + return &editorModes->second; } else { @@ -111,11 +111,11 @@ namespace AzToolsFramework size_t ViewportEditorModeTracker::GetTrackedViewportCount() const { - return m_viewportEditorModeStates.size(); + return m_viewportEditorModesMap.size(); } bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const { - return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; + return m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id) > 0; } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 0ec5a31ddd..222e5af829 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -56,7 +56,7 @@ namespace AzToolsFramework bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: - using ViewportEditorModess = AZStd::unordered_map; - ViewportEditorModess m_viewportEditorModeStates; //!< Editor mode state per viewport. + using ViewportEditorModesMap = AZStd::unordered_map; + ViewportEditorModesMap m_viewportEditorModesMap; //!< Editor mode state per viewport. }; } // namespace AzToolsFramework From 61618e66d3f459f771e3351b38923b33809031f8 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 15 Sep 2021 12:41:08 -0700 Subject: [PATCH 023/115] Fixed a build dependency issue between libpng and zlib on android, thanks to suggestion from @lumberyard-employee-dm Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- Gems/Atom/Feature/Common/Code/CMakeLists.txt | 7 ------- Gems/Atom/Utils/Code/CMakeLists.txt | 1 - .../Platform/Android/BuiltInPackages_android.cmake | 2 +- .../Platform/Windows/BuiltInPackages_windows.cmake | 2 +- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/CMakeLists.txt b/Gems/Atom/Feature/Common/Code/CMakeLists.txt index 3a38aefe02..b8c414dcc6 100644 --- a/Gems/Atom/Feature/Common/Code/CMakeLists.txt +++ b/Gems/Atom/Feature/Common/Code/CMakeLists.txt @@ -83,13 +83,6 @@ ly_add_target( Include BUILD_DEPENDENCIES PRIVATE - # For some reason zlib and libpng need to be declared here, otherwise libAtom_Feature_Common.so will fail to link - # when building for Android. These libraries are appropriately indicated in Atom/Utils's CCmakeLists.txt and those dependencies are - # supposed to be inherited here through the PUBLIC dependencies chaining ... but something is amiss. libpng and zlib were both - # appearing in the link command so it isn't clear why it was failing. Perhaps it was because libpng appeared before zlib - # in the link command? Somehow repeating them here works around this issue. - 3rdParty::libpng - 3rdParty::zlib AZ::AzCore AZ::AzFramework Gem::Atom_Feature_Common.Static diff --git a/Gems/Atom/Utils/Code/CMakeLists.txt b/Gems/Atom/Utils/Code/CMakeLists.txt index 0781100e9a..89bc8dd0a5 100644 --- a/Gems/Atom/Utils/Code/CMakeLists.txt +++ b/Gems/Atom/Utils/Code/CMakeLists.txt @@ -24,7 +24,6 @@ ly_add_target( Gem::Atom_RHI.Public PUBLIC Gem::Atom_RHI.Reflect - 3rdParty::zlib 3rdParty::libpng ) diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index 333b9a5444..297707adf1 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -24,7 +24,7 @@ ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-android TARGETS Phy ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-android TARGETS mikkelsen PACKAGE_HASH 075e8e4940884971063b5a9963014e2e517246fa269c07c7dc55b8cf2cd99705) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-android TARGETS googletest PACKAGE_HASH 95671be75287a61c9533452835c3647e9c1b30f81b34b43bcb0ec1997cc23894) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-android TARGETS GoogleBenchmark PACKAGE_HASH 20b46e572211a69d7d94ddad1c89ec37bb958711d6ad4025368ac89ea83078fb) -ly_associate_package(PACKAGE_NAME libpng-1.6.37-android TARGETS libpng PACKAGE_HASH 72be3859de38559ed45e4383bc480ad9cc1c080fea2c4d6dd3946c2fb22ad5bb) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-android TARGETS libpng PACKAGE_HASH 51d3ec1559c5595196c11e11674cf5745989d3073bf33dabc6697e3eee77a1cc) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-android TARGETS libsamplerate PACKAGE_HASH bf13662afe65d02bcfa16258a4caa9b875534978227d6f9f36c9cfa92b3fb12b) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-android TARGETS OpenSSL PACKAGE_HASH 4036d4019d722f0e1b7a1621bf60b5a17ca6a65c9c78fd8701cee1131eec8480) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-android TARGETS zlib PACKAGE_HASH 85b730b97176772538cfcacd6b6aaf4655fc2d368d134d6dd55e02f28f183826) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index ba5658df0e..a6fb3fbddc 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -42,7 +42,7 @@ ly_associate_package(PACKAGE_NAME d3dx12-headers-rev1-windows ly_associate_package(PACKAGE_NAME pyside2-qt-5.15.1-rev2-windows TARGETS pyside2 PACKAGE_HASH c90f3efcc7c10e79b22a33467855ad861f9dbd2e909df27a5cba9db9fa3edd0f) ly_associate_package(PACKAGE_NAME openimageio-2.1.16.0-rev2-windows TARGETS OpenImageIO PACKAGE_HASH 85a2a6cf35cbc4c967c56ca8074babf0955c5b490c90c6e6fd23c78db99fc282) ly_associate_package(PACKAGE_NAME qt-5.15.2-rev4-windows TARGETS Qt PACKAGE_HASH a4634caaf48192cad5c5f408504746e53d338856148285057274f6a0ccdc071d) -ly_associate_package(PACKAGE_NAME libpng-1.6.37-windows TARGETS libpng PACKAGE_HASH 011079ecbc09c22852eecd860c70dd89f8c2f923c09be87fec4e18ce1e55d4e7) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-windows TARGETS libpng PACKAGE_HASH aa20c894fbd7cdaea585a54e37620b3454a7e414a58128acd68ccf6fe76c47d6) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-windows TARGETS libsamplerate PACKAGE_HASH dcf3c11a96f212a52e2c9241abde5c364ee90b0f32fe6eeb6dcdca01d491829f) ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev1-windows TARGETS OpenMesh PACKAGE_HASH 1c1df639358526c368e790dfce40c45cbdfcfb1c9a041b9d7054a8949d88ee77) ly_associate_package(PACKAGE_NAME civetweb-1.8-rev1-windows TARGETS civetweb PACKAGE_HASH 36d0e58a59bcdb4dd70493fb1b177aa0354c945b06c30416348fd326cf323dd4) From f95986f4432dd40a0473f8dfeb3d34f94538a8a4 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 15 Sep 2021 23:33:48 -0700 Subject: [PATCH 024/115] Updated linux build to use new libpng package. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index d1bfcfb031..92030a39e0 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -37,7 +37,7 @@ ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-linux ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-linux TARGETS GoogleBenchmark PACKAGE_HASH 4038878f337fc7e0274f0230f71851b385b2e0327c495fc3dd3d1c18a807928d) ly_associate_package(PACKAGE_NAME unwind-1.2.1-linux TARGETS unwind PACKAGE_HASH 3453265fb056e25432f611a61546a25f60388e315515ad39007b5925dd054a77) ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-linux TARGETS Qt PACKAGE_HASH 76b395897b941a173002845c7219a5f8a799e44b269ffefe8091acc048130f28) -ly_associate_package(PACKAGE_NAME libpng-1.6.37-linux TARGETS libpng PACKAGE_HASH 0000000000000000000000000000000000000000000000000000000000000000) +ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-linux TARGETS libpng PACKAGE_HASH 896451999f1de76375599aec4b34ae0573d8d34620d9ab29cc30b8739c265ba6) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-linux TARGETS libsamplerate PACKAGE_HASH 41643c31bc6b7d037f895f89d8d8d6369e906b92eff42b0fe05ee6a100f06261) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-linux TARGETS OpenSSL PACKAGE_HASH b779426d1e9c5ddf71160d5ae2e639c3b956e0fb5e9fcaf9ce97c4526024e3bc) ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-linux TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 88c4a359325d749bc34090b9ac466424847f3b71ba0de15045cf355c17c07099) From c713077e070e0109254a4abb6bacc881eef01df5 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 17 Sep 2021 17:02:28 +0100 Subject: [PATCH 025/115] Rename Enter/ExitMode to Register/UnregisterMode. Signed-off-by: John --- .../API/ViewportEditorModeTrackerInterface.h | 8 ++-- .../ViewportEditorModeTracker.cpp | 10 ++-- .../ViewportEditorModeTracker.h | 6 +-- .../Viewport/ViewportEditorModeTests.cpp | 46 +++++++++---------- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 4bafdc3d01..062d326046 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -21,11 +21,11 @@ namespace AzToolsFramework virtual ~ViewportEditorModeTrackerInterface() = default; - //! Enters the specified editor mode for the specified viewport. - virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + //! Registers the specified editor mode as active for the specified viewport. + virtual void RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; - //! Exits the specified editor mode for the specified viewport. - virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + //! Unregisters the specified editor mode as active for the specified viewport. + virtual void UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 511024daed..1dfc4ac035 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -59,19 +59,19 @@ namespace AzToolsFramework } } - void ViewportEditorModeTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModeTracker::RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { auto& editorModes = m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; AZ_Warning( ViewportEditorModeLogWindow, !editorModes.IsModeActive(mode), AZStd::string::format( - "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); editorModes.SetModeActive(mode); ViewportEditorModeNotificationsBus::Event( viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModes, mode); } - void ViewportEditorModeTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModeTracker::UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { ViewportEditorModes* editorModes = nullptr; if (m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id)) @@ -80,12 +80,12 @@ namespace AzToolsFramework AZ_Warning( ViewportEditorModeLogWindow, editorModes->IsModeActive(mode), AZStd::string::format( - "Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); } else { AZ_Warning( - ViewportEditorModeLogWindow, false, "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", + ViewportEditorModeLogWindow, false, "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(mode), viewportEditorModeInfo.m_id); editorModes = &m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 222e5af829..e766bd29b9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -48,9 +48,9 @@ namespace AzToolsFramework //! Unregisters this object with the AZ::Interface. void UnregisterInterface(); - // ViewportEditorModeTrackerInterface ... - void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + // ViewportEditorModeTrackerInterface overrides ... + void RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + void UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetTrackedViewportCount() const override; bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 7eb4f68d87..ac61a20bf6 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -73,7 +73,7 @@ namespace UnitTest struct ReceivedEvents { bool m_onEnter = false; - bool m_onLeave = false; + bool m_onExit = false; }; using EditModeTracker = AZStd::unordered_map; @@ -106,7 +106,7 @@ namespace UnitTest virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { - m_editorModes[mode].m_onLeave = true; + m_editorModes[mode].m_onExit = true; } private: @@ -286,7 +286,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetTrackedViewportCount(), 0); } - TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) + TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -295,7 +295,7 @@ namespace UnitTest // When a mode is activated for that viewport const auto editorMode = ViewportEditorMode::Default; - m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); // Expect that viewport to now be tracked @@ -306,7 +306,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -316,8 +316,8 @@ namespace UnitTest // When a mode is deactivated for that viewport const auto editorMode = ViewportEditorMode::Default; UnitTest::ErrorHandler errorHandler(AZStd::string::format( - "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", static_cast(editorMode), viewportid).c_str()); - m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); + "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(editorMode), viewportid).c_str()); + m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); // Expect a warning to be issued due to no precursor activation of that mode EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); @@ -338,7 +338,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); } - TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -347,13 +347,13 @@ namespace UnitTest const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = AZStd::string::format( - "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); { UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is activated for the viewport - m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); // Expect no warning to be issued as there is no duplicate activation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); @@ -367,7 +367,7 @@ namespace UnitTest { // When the mode is activated again for the viewport UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); // Expect a warning to be issued for the duplicate activation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); @@ -380,7 +380,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeTrackerTestFixture, ExitingViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -389,14 +389,14 @@ namespace UnitTest const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = - AZStd::string::format("Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + AZStd::string::format("Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); { UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is activated and then deactivated for the viewport - m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); - m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); // Expect no warning to be issued as there is no duplicate deactivation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); @@ -411,7 +411,7 @@ namespace UnitTest UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is deactivated again for the viewport - m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); // Expect a warning to be issued for the duplicate deactivation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); @@ -426,7 +426,7 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - EnteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeEnterEventForAllSubscribers) + RegisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeRegisterEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -440,7 +440,7 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.EnterMode({ mode }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -453,13 +453,13 @@ namespace UnitTest const auto& expectedEditorModeSet = editorModes.find(editorMode); EXPECT_NE(expectedEditorModeSet, editorModes.end()); EXPECT_TRUE(expectedEditorModeSet->second.m_onEnter); - EXPECT_FALSE(expectedEditorModeSet->second.m_onLeave); + EXPECT_FALSE(expectedEditorModeSet->second.m_onExit); } } TEST_F( ViewportEditorModePublisherTestFixture, - ExitingViewportEditorModesForExistingIdPublishesOnViewportEditorModeExitEventForAllSubscribers) + UnregisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeUnregisterEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -472,8 +472,8 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.EnterMode({ mode }, editorMode); - m_viewportEditorModeTracker.ExitMode({ mode }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ mode }, editorMode); + m_viewportEditorModeTracker.UnregisterMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -486,7 +486,7 @@ namespace UnitTest const auto& expectedEditorModeSet = editorModes.find(editorMode); EXPECT_NE(expectedEditorModeSet, editorModes.end()); EXPECT_TRUE(expectedEditorModeSet->second.m_onEnter); - EXPECT_TRUE(expectedEditorModeSet->second.m_onLeave); + EXPECT_TRUE(expectedEditorModeSet->second.m_onExit); } } } // namespace UnitTest From 0c79bbd7800c49b01ca9cc8051d5dfb63b2cb9f8 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 17 Sep 2021 17:38:45 +0100 Subject: [PATCH 026/115] Error and warning msgs now return AZ::Outcomes. Signed-off-by: John --- .../API/ViewportEditorModeTrackerInterface.h | 7 +- .../ViewportEditorModeTracker.cpp | 70 ++++++++---- .../ViewportEditorModeTracker.h | 8 +- .../Viewport/ViewportEditorModeTests.cpp | 104 +++++++++--------- 4 files changed, 114 insertions(+), 75 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 062d326046..ae4f3424eb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include namespace AzToolsFramework @@ -22,10 +23,12 @@ namespace AzToolsFramework virtual ~ViewportEditorModeTrackerInterface() = default; //! Registers the specified editor mode as active for the specified viewport. - virtual void RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + virtual AZ::Outcome RegisterMode( + const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Unregisters the specified editor mode as active for the specified viewport. - virtual void UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + virtual AZ::Outcome UnregisterMode( + const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 1dfc4ac035..36c1b09be7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -13,28 +13,32 @@ namespace AzToolsFramework { static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; - void ViewportEditorModes::SetModeActive(ViewportEditorMode mode) + AZ::Outcome ViewportEditorModes::SetModeActive(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) { m_editorModes[modeIndex] = true; + return AZ::Success(); } else { - AZ_Error(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex) + return AZ::Failure( + AZStd::string::format(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex)); } } - void ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) + AZ::Outcome ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) { m_editorModes[modeIndex] = false; + return AZ::Success(); } else { - AZ_Error(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex) + return AZ::Failure( + AZStd::string::format(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex)); } } @@ -59,41 +63,67 @@ namespace AzToolsFramework } } - void ViewportEditorModeTracker::RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + AZ::Outcome ViewportEditorModeTracker::RegisterMode( + const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { auto& editorModes = m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; - AZ_Warning( - ViewportEditorModeLogWindow, !editorModes.IsModeActive(mode), - AZStd::string::format( - "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); - editorModes.SetModeActive(mode); + if (editorModes.IsModeActive(mode)) + { + return AZ::Failure(AZStd::string::format( + "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); + } + + if (const auto result = editorModes.SetModeActive(mode); + !result.IsSuccess()) + { + return result; + } + ViewportEditorModeNotificationsBus::Event( viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModes, mode); + + return AZ::Success(); } - void ViewportEditorModeTracker::UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + AZ::Outcome ViewportEditorModeTracker::UnregisterMode( + const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { ViewportEditorModes* editorModes = nullptr; + bool modeWasActive = true; if (m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id)) { editorModes = &m_viewportEditorModesMap.at(viewportEditorModeInfo.m_id); - AZ_Warning( - ViewportEditorModeLogWindow, editorModes->IsModeActive(mode), - AZStd::string::format( - "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + if (!editorModes->IsModeActive(mode)) + { + return AZ::Failure(AZStd::string::format( + "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); + } } else { - AZ_Warning( - ViewportEditorModeLogWindow, false, "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", - static_cast(mode), viewportEditorModeInfo.m_id); - + modeWasActive = false; editorModes = &m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; } - editorModes->SetModeInactive(mode); + if(const auto result = editorModes->SetModeInactive(mode); + !result.IsSuccess()) + { + return result; + } + ViewportEditorModeNotificationsBus::Event( viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModes, mode); + + if (modeWasActive) + { + return AZ::Success(); + } + else + { + return AZ::Failure(AZStd::string::format( + "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(mode), + viewportEditorModeInfo.m_id)); + } } const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index e766bd29b9..d67ea5d725 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -26,10 +26,10 @@ namespace AzToolsFramework static constexpr AZ::u8 NumEditorModes = 4; //! Sets the specified mode as active. - void SetModeActive(ViewportEditorMode mode); + AZ::Outcome SetModeActive(ViewportEditorMode mode); // Sets the specified mode as inactive. - void SetModeInactive(ViewportEditorMode mode); + AZ::Outcome SetModeInactive(ViewportEditorMode mode); // ViewportEditorModesInterface ... bool IsModeActive(ViewportEditorMode mode) const override; @@ -49,8 +49,8 @@ namespace AzToolsFramework void UnregisterInterface(); // ViewportEditorModeTrackerInterface overrides ... - void RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - void UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + AZ::Outcome RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + AZ::Outcome UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetTrackedViewportCount() const override; bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index ac61a20bf6..6103482f05 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -19,11 +19,23 @@ namespace UnitTest using ViewportId = ViewportEditorModeInfo::IdType; using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; + void SetModeActiveAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) + { + const auto result = editorModeState.SetModeActive(mode); + EXPECT_TRUE(result.IsSuccess()); + } + + void SetModeInactiveAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) + { + const auto result = editorModeState.SetModeInactive(mode); + EXPECT_TRUE(result.IsSuccess()); + } + void SetAllModesActive(ViewportEditorModes& editorModeState) { for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { - editorModeState.SetModeActive(static_cast(mode)); + SetModeActiveAndExpectSuccess(editorModeState, static_cast(mode)); } } @@ -31,7 +43,7 @@ namespace UnitTest { for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { - editorModeState.SetModeInactive(static_cast(mode)); + SetModeInactiveAndExpectSuccess(editorModeState, static_cast(mode)); } } @@ -155,7 +167,7 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { - m_editorModes.SetModeActive(m_selectedEditorMode); + SetModeActiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { @@ -174,7 +186,7 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { SetAllModesActive(m_editorModes); - m_editorModes.SetModeInactive(m_selectedEditorMode); + SetModeInactiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { @@ -196,7 +208,9 @@ namespace UnitTest { // Given only the selected mode active SetAllModesInactive(m_editorModes); - m_editorModes.SetModeActive(m_selectedEditorMode); + { + SetModeActiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); + } const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -205,7 +219,7 @@ namespace UnitTest } // When other modes are activated - m_editorModes.SetModeActive(editorMode); + SetModeActiveAndExpectSuccess(m_editorModes, editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -230,7 +244,7 @@ namespace UnitTest { // Given only the selected mode inactive SetAllModesActive(m_editorModes); - m_editorModes.SetModeInactive(m_selectedEditorMode); + SetModeInactiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -239,7 +253,7 @@ namespace UnitTest } // When other modes are deactivated - m_editorModes.SetModeInactive(editorMode); + SetModeInactiveAndExpectSuccess(m_editorModes, editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -267,18 +281,16 @@ namespace UnitTest AzToolsFramework::ViewportEditorMode::Focus, AzToolsFramework::ViewportEditorMode::Pick)); - TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveIssuesErrorMsg) + TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveReturnsError) { - UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModes.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); - EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); + const auto result = m_editorModes.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); + EXPECT_FALSE(result.IsSuccess()); } - TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveIssuesErrorMsg) + TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveReturnsError) { - UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModes.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); - EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); + const auto result = m_editorModes.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); + EXPECT_FALSE(result.IsSuccess()); } TEST_F(ViewportEditorModeTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) @@ -306,7 +318,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -315,12 +327,13 @@ namespace UnitTest // When a mode is deactivated for that viewport const auto editorMode = ViewportEditorMode::Default; - UnitTest::ErrorHandler errorHandler(AZStd::string::format( - "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(editorMode), viewportid).c_str()); - m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + const auto expectedErrorMsg = AZStd::string::format( + "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(editorMode), viewportid); + const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); - // Expect a warning to be issued due to no precursor activation of that mode - EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + // Expect an error due to no precursor activation of that mode + EXPECT_FALSE(result.IsSuccess()); + EXPECT_EQ(result.GetError(), expectedErrorMsg); // Expect that viewport to now be tracked const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); @@ -338,7 +351,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); } - TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateReturnsError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -346,17 +359,12 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; - const auto expectedWarning = AZStd::string::format( - "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); - { - UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - // When the mode is activated for the viewport - m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); - // Expect no warning to be issued as there is no duplicate activation - EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); + // Expect no error as there is no duplicate activation + EXPECT_TRUE(result.IsSuccess()); // Expect the mode to be active for the viewport const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); @@ -366,11 +374,13 @@ namespace UnitTest } { // When the mode is activated again for the viewport - UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); - // Expect a warning to be issued for the duplicate activation - EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + // Expect an error for the duplicate activation + const auto expectedErrorMsg = AZStd::string::format( + "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + EXPECT_FALSE(result.IsSuccess()); + EXPECT_EQ(result.GetError(), expectedErrorMsg); // Expect the mode to still be active for the viewport const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); @@ -380,7 +390,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateReturnssError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -388,18 +398,13 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; - const auto expectedWarning = - AZStd::string::format("Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); - { - UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - // When the mode is activated and then deactivated for the viewport m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); - m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); - // Expect no warning to be issued as there is no duplicate deactivation - EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); + // Expect no error as there is no duplicate deactivation + EXPECT_TRUE(result.IsSuccess()); // Expect the mode to be inctive for the viewport const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); @@ -408,13 +413,14 @@ namespace UnitTest EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } { - UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - // When the mode is deactivated again for the viewport - m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); - // Expect a warning to be issued for the duplicate deactivation - EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + // Expect an error for the duplicate deactivation + const auto expectedErrorMsg = AZStd::string::format( + "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + EXPECT_FALSE(result.IsSuccess()); + EXPECT_EQ(result.GetError(), expectedErrorMsg); // Expect the mode to still be inactive for the viewport const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); From c2abd2d74f67880305abede3973666d618c9853e Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 17 Sep 2021 22:19:31 -0700 Subject: [PATCH 027/115] Updated the naming convention for material property "names" vs "IDs". A "property name" is the name of the just the property without regard to the group that it's in. A "group name" is the name of the group. And a "property ID" is the full unique name of a property in the form "groupName.propertyName". This is important preparation for upcoming changes where property sets can contain other property sets, and property IDs can be arbitrarily long like "layer1.baseColor.factor" for example. The naming changes include variables, some code comments, and the .materialtype file format. I was able to make these changes in a backward compatible way so a property or group "id" field has been replaced with a "name" field, but "id" is still supported for compatibility. StandardPBR, EnhancedPBR, StandardMultilayerPBR, and Skin have all been updated. Note that MinimalPBR has not been updated, proving that backward compatibility works. (We can update this one too at some point though). Testing: Opened up materials in the material editor. Ran AtomSampleViewer in dx12 and vulkan with no new failures. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Materials/Types/EnhancedPBR.materialtype | 456 +++++----- .../Assets/Materials/Types/Skin.materialtype | 312 +++---- .../Types/StandardMultilayerPBR.materialtype | 812 +++++++++--------- .../Materials/Types/StandardPBR.materialtype | 322 +++---- .../Material/MaterialTypeSourceData.h | 16 +- .../Atom/RPI.Public/Material/Material.h | 4 +- .../Material/MaterialPropertiesLayout.h | 2 +- .../Material/MaterialPropertySerializer.cpp | 11 +- .../MaterialPropertyValueSerializer.cpp | 14 +- .../Material/MaterialTypeSourceData.cpp | 58 +- .../Source/RPI.Public/Material/Material.cpp | 4 +- .../Material/MaterialPropertiesLayout.cpp | 4 +- .../Material/MaterialSourceDataTests.cpp | 8 +- .../Document/AtomToolsDocument.h | 6 +- .../DynamicProperty/DynamicProperty.h | 4 +- .../Inspector/InspectorRequestBus.h | 18 +- .../Inspector/InspectorWidget.h | 26 +- .../Source/Document/AtomToolsDocument.cpp | 12 +- .../DynamicProperty/DynamicProperty.cpp | 2 +- .../Code/Source/Inspector/InspectorWidget.cpp | 76 +- .../Code/Source/Util/MaterialPropertyUtil.cpp | 2 +- .../Code/Source/Document/MaterialDocument.cpp | 44 +- .../Code/Source/Document/MaterialDocument.h | 6 +- .../MaterialInspector/MaterialInspector.cpp | 52 +- .../MaterialInspector/MaterialInspector.h | 8 +- .../Window/SettingsDialog/SettingsWidget.cpp | 8 +- .../ViewportSettingsInspector.cpp | 34 +- .../ViewportSettingsInspector.h | 8 +- .../EditorMaterialComponentInspector.cpp | 34 +- .../EditorMaterialComponentInspector.h | 2 +- .../Material/EditorMaterialComponentUtil.cpp | 6 +- .../EditorMaterialModelUvNameMapInspector.cpp | 14 +- 32 files changed, 1196 insertions(+), 1189 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype index 9b2c465352..bed3b69c4c 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype @@ -4,88 +4,88 @@ "version": 3, "groups": [ { - "id": "baseColor", + "name": "baseColor", "displayName": "Base Color", "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." }, { - "id": "metallic", + "name": "metallic", "displayName": "Metallic", "description": "Properties for configuring whether the surface is metallic or not." }, { - "id": "roughness", + "name": "roughness", "displayName": "Roughness", "description": "Properties for configuring how rough the surface appears." }, { - "id": "specularF0", + "name": "specularF0", "displayName": "Specular Reflectance f0", "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." }, { - "id": "normal", + "name": "normal", "displayName": "Normal", "description": "Properties related to configuring surface normal." }, { - "id": "detailLayerGroup", + "name": "detailLayerGroup", "displayName": "Detail Layer", "description": "Properties for Fine Details Layer." }, { - "id": "detailUV", + "name": "detailUV", "displayName": "Detail Layer UV", "description": "Properties for modifying detail layer UV." }, { - "id": "anisotropy", + "name": "anisotropy", "displayName": "Anisotropic Material Response", "description": "How much is this material response anisotropic." }, { - "id": "occlusion", + "name": "occlusion", "displayName": "Occlusion", "description": "Properties for baked textures that represent geometric occlusion of light." }, { - "id": "emissive", + "name": "emissive", "displayName": "Emissive", "description": "Properties to add light emission, independent of other lights in the scene." }, { - "id": "subsurfaceScattering", + "name": "subsurfaceScattering", "displayName": "Subsurface Scattering", "description": "Properties for configuring subsurface scattering effects." }, { - "id": "clearCoat", + "name": "clearCoat", "displayName": "Clear Coat", "description": "Properties for configuring gloss clear coat" }, { - "id": "parallax", + "name": "parallax", "displayName": "Displacement", "description": "Properties for parallax effect produced by a height map." }, { - "id": "opacity", + "name": "opacity", "displayName": "Opacity", "description": "Properties for configuring the materials transparency." }, { - "id": "uv", + "name": "uv", "displayName": "UVs", "description": "Properties for configuring UV transforms." }, { // Note: this property group is used in the DiffuseGlobalIllumination pass and not by the main forward shader - "id": "irradiance", + "name": "irradiance", "displayName": "Irradiance", "description": "Properties for configuring the irradiance used in global illumination." }, { - "id": "general", + "name": "general", "displayName": "General Settings", "description": "General settings." } @@ -93,97 +93,97 @@ "properties": { "general": [ { - "id": "applySpecularAA", + "name": "applySpecularAA", "displayName": "Apply Specular AA", "description": "Whether to apply specular anti-aliasing in the shader.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_applySpecularAA" + "name": "o_applySpecularAA" } }, { - "id": "enableShadows", + "name": "enableShadows", "displayName": "Enable Shadows", "description": "Whether to use the shadow maps.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableShadows" + "name": "o_enableShadows" } }, { - "id": "enableDirectionalLights", + "name": "enableDirectionalLights", "displayName": "Enable Directional Lights", "description": "Whether to use directional lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableDirectionalLights" + "name": "o_enableDirectionalLights" } }, { - "id": "enablePunctualLights", + "name": "enablePunctualLights", "displayName": "Enable Punctual Lights", "description": "Whether to use punctual lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enablePunctualLights" + "name": "o_enablePunctualLights" } }, { - "id": "enableAreaLights", + "name": "enableAreaLights", "displayName": "Enable Area Lights", "description": "Whether to use area lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableAreaLights" + "name": "o_enableAreaLights" } }, { - "id": "enableIBL", + "name": "enableIBL", "displayName": "Enable IBL", "description": "Whether to use Image Based Lighting (IBL).", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableIBL" + "name": "o_enableIBL" } }, { - "id": "forwardPassIBLSpecular", + "name": "forwardPassIBLSpecular", "displayName": "Forward Pass IBL Specular", "description": "Whether to apply IBL specular in the forward pass.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_materialUseForwardPassIBLSpecular" + "name": "o_materialUseForwardPassIBLSpecular" } } ], "baseColor": [ { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_baseColor" + "name": "m_baseColor" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", "type": "Float", @@ -192,28 +192,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_baseColorFactor" + "name": "m_baseColorFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Base color texture map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_baseColorMap" + "name": "m_baseColorMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Base color map UV set", "type": "Enum", @@ -221,11 +221,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_baseColorMapUvIndex" + "name": "m_baseColorMapUvIndex" } }, { - "id": "textureBlendMode", + "name": "textureBlendMode", "displayName": "Texture Blend Mode", "description": "Selects the equation to use when combining Color, Factor, and Texture.", "type": "Enum", @@ -233,13 +233,13 @@ "defaultValue": "Multiply", "connection": { "type": "ShaderOption", - "id": "o_baseColorTextureBlendMode" + "name": "o_baseColorTextureBlendMode" } } ], "metallic": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "This value is linear, black is non-metal and white means raw metal.", "type": "Float", @@ -248,28 +248,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_metallicFactor" + "name": "m_metallicFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_metallicMap" + "name": "m_metallicMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Metallic map UV set", "type": "Enum", @@ -277,30 +277,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_metallicMapUvIndex" + "name": "m_metallicMapUvIndex" } } ], "roughness": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface roughness.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_roughnessMap" + "name": "m_roughnessMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Roughness map UV set", "type": "Enum", @@ -308,12 +308,12 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_roughnessMapUvIndex" + "name": "m_roughnessMapUvIndex" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "lowerBound", + "name": "lowerBound", "displayName": "Lower Bound", "description": "The roughness value that corresponds to black in the texture.", "type": "Float", @@ -322,12 +322,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughnessLowerBound" + "name": "m_roughnessLowerBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "upperBound", + "name": "upperBound", "displayName": "Upper Bound", "description": "The roughness value that corresponds to white in the texture.", "type": "Float", @@ -336,12 +336,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughnessUpperBound" + "name": "m_roughnessUpperBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Controls the roughness value", "type": "Float", @@ -350,24 +350,24 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughnessFactor" + "name": "m_roughnessFactor" } } ], "anisotropy": [ { - "id": "enableAnisotropy", + "name": "enableAnisotropy", "displayName": "Enable Anisotropy", "description": "Enable anisotropic surface response for non uniform reflection along the axis", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_enableAnisotropy" + "name": "o_enableAnisotropy" } }, { - "id": "factor", + "name": "factor", "displayName": "Anisotropy Factor", "description": "Strength factor for the anisotropy: negative = along v, positive = along u", "type": "Float", @@ -376,11 +376,11 @@ "max": 0.95, "connection": { "type": "ShaderInput", - "id": "m_anisotropicFactor" + "name": "m_anisotropicFactor" } }, { - "id": "anisotropyAngle", + "name": "anisotropyAngle", "displayName": "Anisotropy Angle", "description": "Anisotropy direction of major reflection axis: 0 = 0 degrees, 1.0 = 180 degrees", "type": "Float", @@ -389,13 +389,13 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_anisotropicAngle" + "name": "m_anisotropicAngle" } } ], "specularF0": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", "type": "Float", @@ -404,28 +404,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_specularF0Factor" + "name": "m_specularF0Factor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface reflectance.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_specularF0Map" + "name": "m_specularF0Map" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Specular reflection map UV set", "type": "Enum", @@ -433,31 +433,31 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_specularF0MapUvIndex" + "name": "m_specularF0MapUvIndex" } }, // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR { - "id": "enableMultiScatterCompensation", + "name": "enableMultiScatterCompensation", "displayName": "Multiscattering Compensation", "description": "Whether to enable multiple scattering compensation.", "type": "Bool", "connection": { "type": "ShaderOption", - "id": "o_specularF0_enableMultiScatterCompensation" + "name": "o_specularF0_enableMultiScatterCompensation" } } ], "clearCoat": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable clear coat", "type": "Bool", "defaultValue": false }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the percentage of effect applied", "type": "Float", @@ -466,28 +466,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_clearCoatFactor" + "name": "m_clearCoatFactor" } }, { - "id": "influenceMap", + "name": "influenceMap", "displayName": " Influence Map", "description": "Strength factor texture", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_clearCoatInfluenceMap" + "name": "m_clearCoatInfluenceMap" } }, { - "id": "useInfluenceMap", + "name": "useInfluenceMap", "displayName": " Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "influenceMapUv", + "name": "influenceMapUv", "displayName": " UV", "description": "Strength factor map UV set", "type": "Enum", @@ -495,11 +495,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_clearCoatInfluenceMapUvIndex" + "name": "m_clearCoatInfluenceMapUvIndex" } }, { - "id": "roughness", + "name": "roughness", "displayName": "Roughness", "description": "Clear coat layer roughness", "type": "Float", @@ -508,28 +508,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_clearCoatRoughness" + "name": "m_clearCoatRoughness" } }, { - "id": "roughnessMap", + "name": "roughnessMap", "displayName": " Roughness Map", "description": "Texture for defining surface roughness", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_clearCoatRoughnessMap" + "name": "m_clearCoatRoughnessMap" } }, { - "id": "useRoughnessMap", + "name": "useRoughnessMap", "displayName": " Use Texture", "description": "Whether to use the texture, or just default to the roughness value.", "type": "Bool", "defaultValue": true }, { - "id": "roughnessMapUv", + "name": "roughnessMapUv", "displayName": " UV", "description": "Roughness map UV set", "type": "Enum", @@ -537,11 +537,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_clearCoatRoughnessMapUvIndex" + "name": "m_clearCoatRoughnessMapUvIndex" } }, { - "id": "normalStrength", + "name": "normalStrength", "displayName": "Normal Strength", "description": "Scales the impact of the clear coat normal map", "type": "Float", @@ -550,28 +550,28 @@ "max": 2.0, "connection": { "type": "ShaderInput", - "id": "m_clearCoatNormalStrength" + "name": "m_clearCoatNormalStrength" } }, { - "id": "normalMap", + "name": "normalMap", "displayName": "Normal Map", "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_clearCoatNormalMap" + "name": "m_clearCoatNormalMap" } }, { - "id": "useNormalMap", + "name": "useNormalMap", "displayName": " Use Texture", "description": "Whether to use the normal map", "type": "Bool", "defaultValue": true }, { - "id": "normalMapUv", + "name": "normalMapUv", "displayName": " UV", "description": "Normal map UV set", "type": "Enum", @@ -579,30 +579,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_clearCoatNormalMapUvIndex" + "name": "m_clearCoatNormalMapUvIndex" } } ], "normal": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface normal direction.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_normalMap" + "name": "m_normalMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just rely on vertex normals.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Normal map UV set", "type": "Enum", @@ -610,33 +610,33 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_normalMapUvIndex" + "name": "m_normalMapUvIndex" } }, { - "id": "flipX", + "name": "flipX", "displayName": "Flip X Channel", "description": "Flip tangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_flipNormalX" + "name": "m_flipNormalX" } }, { - "id": "flipY", + "name": "flipY", "displayName": "Flip Y Channel", "description": "Flip bitangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_flipNormalY" + "name": "m_flipNormalY" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the values", "type": "Float", @@ -645,13 +645,13 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_normalFactor" + "name": "m_normalFactor" } } ], "opacity": [ { - "id": "mode", + "name": "mode", "displayName": "Opacity Mode", "description": "Indicates the general approach how transparency is to be applied.", "type": "Enum", @@ -659,11 +659,11 @@ "defaultValue": "Opaque", "connection": { "type": "ShaderOption", - "id": "o_opacity_mode" + "name": "o_opacity_mode" } }, { - "id": "alphaSource", + "name": "alphaSource", "displayName": "Alpha Source", "description": "Indicates whether to get the opacity texture from the Base Color map (Packed) or from a separate greyscale texture (Split).", "type": "Enum", @@ -671,21 +671,21 @@ "defaultValue": "Packed", "connection": { "type": "ShaderOption", - "id": "o_opacity_source" + "name": "o_opacity_source" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface opacity.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_opacityMap" + "name": "m_opacityMap" } }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Opacity map UV set", "type": "Enum", @@ -693,11 +693,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_opacityMapUvIndex" + "name": "m_opacityMapUvIndex" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Factor for cutout threshold and blending", "type": "Float", @@ -706,17 +706,17 @@ "defaultValue": 0.5, "connection": { "type": "ShaderInput", - "id": "m_opacityFactor" + "name": "m_opacityFactor" } }, { - "id": "doubleSided", + "name": "doubleSided", "displayName": "Double-sided", "description": "Whether to render back-faces or just front-faces.", "type": "Bool" }, { - "id": "alphaAffectsSpecular", + "name": "alphaAffectsSpecular", "displayName": "Alpha affects specular", "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", "type": "float", @@ -725,13 +725,13 @@ "defaultValue": 0.0, "connection": { "type": "ShaderInput", - "id": "m_opacityAffectsSpecularFactor" + "name": "m_opacityAffectsSpecularFactor" } } ], "uv": [ { - "id": "center", + "name": "center", "displayName": "Center", "description": "Center point for scaling and rotation transformations.", "type": "vector2", @@ -739,7 +739,7 @@ "defaultValue": [ 0.5, 0.5 ] }, { - "id": "tileU", + "name": "tileU", "displayName": "Tile U", "description": "Scales texture coordinates in U.", "type": "float", @@ -747,7 +747,7 @@ "step": 0.1 }, { - "id": "tileV", + "name": "tileV", "displayName": "Tile V", "description": "Scales texture coordinates in V.", "type": "float", @@ -755,7 +755,7 @@ "step": 0.1 }, { - "id": "offsetU", + "name": "offsetU", "displayName": "Offset U", "description": "Offsets texture coordinates in the U direction.", "type": "float", @@ -764,7 +764,7 @@ "max": 1.0 }, { - "id": "offsetV", + "name": "offsetV", "displayName": "Offset V", "description": "Offsets texture coordinates in the V direction.", "type": "float", @@ -773,7 +773,7 @@ "max": 1.0 }, { - "id": "rotateDegrees", + "name": "rotateDegrees", "displayName": "Rotate", "description": "Rotates the texture coordinates (degrees).", "type": "float", @@ -783,7 +783,7 @@ "step": 1.0 }, { - "id": "scale", + "name": "scale", "displayName": "Scale", "description": "Scales texture coordinates in both U and V.", "type": "float", @@ -793,24 +793,24 @@ ], "occlusion": [ { - "id": "diffuseTextureMap", + "name": "diffuseTextureMap", "displayName": "Diffuse AO", "description": "Texture for defining occlusion area for diffuse ambient lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_diffuseOcclusionMap" + "name": "m_diffuseOcclusionMap" } }, { - "id": "diffuseUseTexture", + "name": "diffuseUseTexture", "displayName": " Use Texture", "description": "Whether to use the Diffuse AO map.", "type": "Bool", "defaultValue": true }, { - "id": "diffuseTextureMapUv", + "name": "diffuseTextureMapUv", "displayName": " UV", "description": "Diffuse AO map UV set.", "type": "Enum", @@ -818,11 +818,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_diffuseOcclusionMapUvIndex" + "name": "m_diffuseOcclusionMapUvIndex" } }, { - "id": "diffuseFactor", + "name": "diffuseFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Diffuse AO", "type": "Float", @@ -831,28 +831,28 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_diffuseOcclusionFactor" + "name": "m_diffuseOcclusionFactor" } }, { - "id": "specularTextureMap", + "name": "specularTextureMap", "displayName": "Specular Cavity", "description": "Texture for defining occlusion area for specular lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_specularOcclusionMap" + "name": "m_specularOcclusionMap" } }, { - "id": "specularUseTexture", + "name": "specularUseTexture", "displayName": " Use Texture", "description": "Whether to use the Specular Cavity map.", "type": "Bool", "defaultValue": true }, { - "id": "specularTextureMapUv", + "name": "specularTextureMapUv", "displayName": " UV", "description": "Specular Cavity map UV set.", "type": "Enum", @@ -860,11 +860,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_specularOcclusionMapUvIndex" + "name": "m_specularOcclusionMapUvIndex" } }, { - "id": "specularFactor", + "name": "specularFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Specular Cavity", "type": "Float", @@ -873,20 +873,20 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_specularOcclusionFactor" + "name": "m_specularOcclusionFactor" } } ], "emissive": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable the emissive group", "type": "Bool", "defaultValue": false }, { - "id": "unit", + "name": "unit", "displayName": "Units", "description": "The photometric units of the Intensity property.", "type": "Enum", @@ -894,18 +894,18 @@ "defaultValue": "Ev100" }, { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_emissiveColor" + "name": "m_emissiveColor" } }, { - "id": "intensity", + "name": "intensity", "displayName": "Intensity", "description": "The amount of energy emitted.", "type": "Float", @@ -916,24 +916,24 @@ "softMax": 16 }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining emissive area.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_emissiveMap" + "name": "m_emissiveMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Emissive map UV set", "type": "Enum", @@ -941,30 +941,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_emissiveMapUvIndex" + "name": "m_emissiveMapUvIndex" } } ], "parallax": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Height Map", "description": "Displacement height map to create parallax effect.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_heightmap" + "name": "m_heightmap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the height map.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Height map UV set", "type": "Enum", @@ -972,11 +972,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_parallaxUvIndex" + "name": "m_parallaxUvIndex" } }, { - "id": "factor", + "name": "factor", "displayName": "Height Map Scale", "description": "The total height of the height map in local model units.", "type": "Float", @@ -985,11 +985,11 @@ "softMax": 0.1, "connection": { "type": "ShaderInput", - "id": "m_heightmapScale" + "name": "m_heightmapScale" } }, { - "id": "offset", + "name": "offset", "displayName": "Offset", "description": "Adjusts the overall displacement amount in local model units.", "type": "Float", @@ -998,11 +998,11 @@ "softMax": 0.1, "connection": { "type": "ShaderInput", - "id": "m_heightmapOffset" + "name": "m_heightmapOffset" } }, { - "id": "algorithm", + "name": "algorithm", "displayName": "Algorithm", "description": "Select the algorithm to use for parallax mapping.", "type": "Enum", @@ -1010,11 +1010,11 @@ "defaultValue": "POM", "connection": { "type": "ShaderOption", - "id": "o_parallax_algorithm" + "name": "o_parallax_algorithm" } }, { - "id": "quality", + "name": "quality", "displayName": "Quality", "description": "Quality of parallax mapping.", "type": "Enum", @@ -1022,46 +1022,46 @@ "defaultValue": "Low", "connection": { "type": "ShaderOption", - "id": "o_parallax_quality" + "name": "o_parallax_quality" } }, { - "id": "pdo", + "name": "pdo", "displayName": "Pixel Depth Offset", "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_parallax_enablePixelDepthOffset" + "name": "o_parallax_enablePixelDepthOffset" } }, { - "id": "showClipping", + "name": "showClipping", "displayName": "Show Clipping", "description": "Highlight areas where the height map is clipped by the mesh surface.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_parallax_highlightClipping" + "name": "o_parallax_highlightClipping" } } ], "subsurfaceScattering": [ { - "id": "enableSubsurfaceScattering", + "name": "enableSubsurfaceScattering", "displayName": "Subsurface Scattering", "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_enableSubsurfaceScattering" + "name": "o_enableSubsurfaceScattering" } }, { - "id": "subsurfaceScatterFactor", + "name": "subsurfaceScatterFactor", "displayName": " Factor", "description": "Strength factor for scaling percentage of subsurface scattering effect applied", "type": "float", @@ -1070,28 +1070,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_subsurfaceScatteringFactor" + "name": "m_subsurfaceScatteringFactor" } }, { - "id": "influenceMap", + "name": "influenceMap", "displayName": " Influence Map", "description": "Texture for controlling the strength of subsurface scattering", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_subsurfaceScatteringInfluenceMap" + "name": "m_subsurfaceScatteringInfluenceMap" } }, { - "id": "useInfluenceMap", + "name": "useInfluenceMap", "displayName": " Use Influence Map", "description": "Whether to use the influence map.", "type": "Bool", "defaultValue": true }, { - "id": "influenceMapUv", + "name": "influenceMapUv", "displayName": " UV", "description": "Influence map UV set", "type": "Enum", @@ -1099,18 +1099,18 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_subsurfaceScatteringInfluenceMapUvIndex" + "name": "m_subsurfaceScatteringInfluenceMapUvIndex" } }, { - "id": "scatterColor", + "name": "scatterColor", "displayName": " Scatter color", "description": "Color of volume light traveled through", "type": "Color", "defaultValue": [ 1.0, 0.27, 0.13 ] }, { - "id": "scatterDistance", + "name": "scatterDistance", "displayName": " Scatter distance", "description": "How far light traveled inside the volume", "type": "float", @@ -1119,7 +1119,7 @@ "softMax": 20.0 }, { - "id": "quality", + "name": "quality", "displayName": " Quality", "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel", "type": "float", @@ -1128,11 +1128,11 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_subsurfaceScatteringQuality" + "name": "m_subsurfaceScatteringQuality" } }, { - "id": "transmissionMode", + "name": "transmissionMode", "displayName": "Transmission", "description": "Algorithm used for calculating transmission", "type": "Enum", @@ -1140,11 +1140,11 @@ "defaultValue": "None", "connection": { "type": "ShaderOption", - "id": "o_transmission_mode" + "name": "o_transmission_mode" } }, { - "id": "thickness", + "name": "thickness", "displayName": " Thickness", "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel", "type": "float", @@ -1153,24 +1153,24 @@ "max": 1.0 }, { - "id": "thicknessMap", + "name": "thicknessMap", "displayName": " Thickness Map", "description": "Texture for controlling per pixel thickness", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_transmissionThicknessMap" + "name": "m_transmissionThicknessMap" } }, { - "id": "useThicknessMap", + "name": "useThicknessMap", "displayName": " Use Thickness Map", "description": "Whether to use the thickness map", "type": "Bool", "defaultValue": true }, { - "id": "thicknessMapUv", + "name": "thicknessMapUv", "displayName": " UV", "description": "Thickness map UV set", "type": "Enum", @@ -1178,18 +1178,18 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_transmissionThicknessMapUvIndex" + "name": "m_transmissionThicknessMapUvIndex" } }, { - "id": "transmissionTint", + "name": "transmissionTint", "displayName": " Transmission Tint", "description": "Color of the volume light traveling through", "type": "Color", "defaultValue": [ 1.0, 0.8, 0.6 ] }, { - "id": "transmissionPower", + "name": "transmissionPower", "displayName": " Power", "description": "How much transmitted light scatter radially ", "type": "float", @@ -1198,7 +1198,7 @@ "softMax": 20.0 }, { - "id": "transmissionDistortion", + "name": "transmissionDistortion", "displayName": " Distortion", "description": "How much light direction distorted towards surface normal", "type": "float", @@ -1207,7 +1207,7 @@ "max": 1.0 }, { - "id": "transmissionAttenuation", + "name": "transmissionAttenuation", "displayName": " Attenuation", "description": "How fast transmitted light fade with thickness", "type": "float", @@ -1216,7 +1216,7 @@ "softMax": 20.0 }, { - "id": "transmissionScale", + "name": "transmissionScale", "displayName": " Scale", "description": "Strength of transmission", "type": "float", @@ -1227,14 +1227,14 @@ ], "detailLayerGroup": [ { - "id": "enableDetailLayer", + "name": "enableDetailLayer", "displayName": "Enable Detail Layer", "description": "Enable detail layer for fine details and scratches", "type": "Bool", "defaultValue": false }, { - "id": "blendDetailFactor", + "name": "blendDetailFactor", "displayName": "Blend Factor", "description": "Scales the overall impact of the detail layer.", "type": "Float", @@ -1243,28 +1243,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_detail_blendFactor" + "name": "m_detail_blendFactor" } }, { - "id": "blendDetailMask", + "name": "blendDetailMask", "displayName": "Blend Mask", "description": "Detailed blend mask for application of the detail maps.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_detail_blendMask_texture" + "name": "m_detail_blendMask_texture" } }, { - "id": "enableDetailMaskTexture", + "name": "enableDetailMaskTexture", "displayName": " Use Texture", "description": "Enable detail blend mask", "type": "Bool", "defaultValue": true }, { - "id": "blendDetailMaskUv", + "name": "blendDetailMaskUv", "displayName": " Blend Mask UV", "description": "Which UV set to use for sampling the detail blend mask", "type": "Enum", @@ -1272,11 +1272,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_detail_blendMask_uvIndex" + "name": "m_detail_blendMask_uvIndex" } }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "Detail Map UVs", "description": "Which UV set to use for detail map sampling", "type": "Enum", @@ -1284,28 +1284,28 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_detail_allMapsUvIndex" + "name": "m_detail_allMapsUvIndex" } }, { - "id": "enableBaseColor", + "name": "enableBaseColor", "displayName": "Enable Base Color", "description": "Enable detail blending for base color", "type": "Bool", "defaultValue": false }, { - "id": "baseColorDetailMap", + "name": "baseColorDetailMap", "displayName": " Texture", "description": "Detailed Base Color Texture", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_detail_baseColor_texture" + "name": "m_detail_baseColor_texture" } }, { - "id": "baseColorDetailBlend", + "name": "baseColorDetailBlend", "displayName": " Blend Factor", "description": "How much to blend the detail layer into the base color.", "type": "Float", @@ -1314,18 +1314,18 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_detail_baseColor_factor" + "name": "m_detail_baseColor_factor" } }, { - "id": "enableNormals", + "name": "enableNormals", "displayName": "Enable Normal", "description": "Enable detail normal map to be used for fine detail normal such as scratches and small dents", "type": "Bool", "defaultValue": false }, { - "id": "normalDetailStrength", + "name": "normalDetailStrength", "displayName": " Factor", "description": "Strength factor for scaling the Detail Normal", "type": "Float", @@ -1334,45 +1334,45 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_detail_normal_factor" + "name": "m_detail_normal_factor" } }, { - "id": "normalDetailMap", + "name": "normalDetailMap", "displayName": " Texture", "description": "Detailed Normal map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_detail_normal_texture" + "name": "m_detail_normal_texture" } }, { - "id": "normalDetailFlipX", + "name": "normalDetailFlipX", "displayName": " Flip X Channel", "description": "Flip Detail tangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_detail_normal_flipX" + "name": "m_detail_normal_flipX" } }, { - "id": "normalDetailFlipY", + "name": "normalDetailFlipY", "displayName": " Flip Y Channel", "description": "Flip Detail bitangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_detail_normal_flipY" + "name": "m_detail_normal_flipY" } } ], "detailUV": [ { - "id": "center", + "name": "center", "displayName": "Center", "description": "Center point for scaling and rotation transformations.", "type": "vector2", @@ -1380,7 +1380,7 @@ "defaultValue": [ 0.5, 0.5 ] }, { - "id": "tileU", + "name": "tileU", "displayName": "Tile U", "description": "Scales texture coordinates in V.", "type": "float", @@ -1388,7 +1388,7 @@ "step": 0.1 }, { - "id": "tileV", + "name": "tileV", "displayName": "Tile V", "description": "Scales texture coordinates in V.", "type": "float", @@ -1396,7 +1396,7 @@ "step": 0.1 }, { - "id": "offsetU", + "name": "offsetU", "displayName": "Offset U", "description": "Offsets texture coordinates in the U direction.", "type": "float", @@ -1405,7 +1405,7 @@ "max": 1.0 }, { - "id": "offsetV", + "name": "offsetV", "displayName": "Offset V", "description": "Offsets texture coordinates in the V direction.", "type": "float", @@ -1414,7 +1414,7 @@ "max": 1.0 }, { - "id": "rotateDegrees", + "name": "rotateDegrees", "displayName": "Rotate", "description": "Rotates the texture coordinates (degrees).", "type": "float", @@ -1424,7 +1424,7 @@ "step": 1.0 }, { - "id": "scale", + "name": "scale", "displayName": "Scale", "description": "Scales texture coordinates in both U and V.", "type": "float", @@ -1435,14 +1435,14 @@ "irradiance": [ // Note: this property group is used in the DiffuseGlobalIllumination pass and not by the main forward shader { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ] }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", "type": "Float", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype index fe86576cf8..0969cc36e8 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype @@ -4,52 +4,52 @@ "version": 3, "groups": [ { - "id": "baseColor", + "name": "baseColor", "displayName": "Base Color", "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." }, { - "id": "roughness", + "name": "roughness", "displayName": "Roughness", "description": "Properties for configuring how rough the surface appears." }, { - "id": "specularF0", + "name": "specularF0", "displayName": "Specular Reflectance f0", "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." }, { - "id": "normal", + "name": "normal", "displayName": "Normal", "description": "Properties related to configuring surface normal." }, { - "id": "detailLayerGroup", + "name": "detailLayerGroup", "displayName": "Detail Layer", "description": "Properties for Fine Details Layer." }, { - "id": "detailUV", + "name": "detailUV", "displayName": "Detail Layer UV", "description": "Properties for modifying detail layer UV." }, { - "id": "occlusion", + "name": "occlusion", "displayName": "Occlusion", "description": "Properties for baked textures that represent geometric occlusion of light." }, { - "id": "subsurfaceScattering", + "name": "subsurfaceScattering", "displayName": "Subsurface Scattering", "description": "Properties for configuring subsurface scattering effects." }, { - "id": "wrinkleLayers", + "name": "wrinkleLayers", "displayName": "Wrinkle Layers", "description": "Properties for wrinkle maps to support morph animation, using vertex color blend weights." }, { - "id": "general", + "name": "general", "displayName": "General Settings", "description": "General settings." } @@ -57,86 +57,86 @@ "properties": { "general": [ { - "id": "applySpecularAA", + "name": "applySpecularAA", "displayName": "Apply Specular AA", "description": "Whether to apply specular anti-aliasing in the shader.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_applySpecularAA" + "name": "o_applySpecularAA" } }, { - "id": "enableShadows", + "name": "enableShadows", "displayName": "Enable Shadows", "description": "Whether to use the shadow maps.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableShadows" + "name": "o_enableShadows" } }, { - "id": "enableDirectionalLights", + "name": "enableDirectionalLights", "displayName": "Enable Directional Lights", "description": "Whether to use directional lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableDirectionalLights" + "name": "o_enableDirectionalLights" } }, { - "id": "enablePunctualLights", + "name": "enablePunctualLights", "displayName": "Enable Punctual Lights", "description": "Whether to use punctual lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enablePunctualLights" + "name": "o_enablePunctualLights" } }, { - "id": "enableAreaLights", + "name": "enableAreaLights", "displayName": "Enable Area Lights", "description": "Whether to use area lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableAreaLights" + "name": "o_enableAreaLights" } }, { - "id": "enableIBL", + "name": "enableIBL", "displayName": "Enable IBL", "description": "Whether to use Image Based Lighting (IBL).", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableIBL" + "name": "o_enableIBL" } } ], "baseColor": [ { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_baseColor" + "name": "m_baseColor" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", "type": "Float", @@ -145,28 +145,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_baseColorFactor" + "name": "m_baseColorFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Base color texture map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_baseColorMap" + "name": "m_baseColorMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Base color map UV set", "type": "Enum", @@ -174,11 +174,11 @@ "defaultValue": "Unwrapped", "connection": { "type": "ShaderInput", - "id": "m_baseColorMapUvIndex" + "name": "m_baseColorMapUvIndex" } }, { - "id": "textureBlendMode", + "name": "textureBlendMode", "displayName": "Texture Blend Mode", "description": "Selects the equation to use when combining Color, Factor, and Texture.", "type": "Enum", @@ -186,30 +186,30 @@ "defaultValue": "Multiply", "connection": { "type": "ShaderOption", - "id": "o_baseColorTextureBlendMode" + "name": "o_baseColorTextureBlendMode" } } ], "roughness": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface roughness.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_roughnessMap" + "name": "m_roughnessMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Roughness map UV set", "type": "Enum", @@ -217,12 +217,12 @@ "defaultValue": "Unwrapped", "connection": { "type": "ShaderInput", - "id": "m_roughnessMapUvIndex" + "name": "m_roughnessMapUvIndex" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "lowerBound", + "name": "lowerBound", "displayName": "Lower Bound", "description": "The roughness value that corresponds to black in the texture.", "type": "Float", @@ -231,12 +231,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughnessLowerBound" + "name": "m_roughnessLowerBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "upperBound", + "name": "upperBound", "displayName": "Upper Bound", "description": "The roughness value that corresponds to white in the texture.", "type": "Float", @@ -245,12 +245,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughnessUpperBound" + "name": "m_roughnessUpperBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Controls the roughness value", "type": "Float", @@ -259,13 +259,13 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughnessFactor" + "name": "m_roughnessFactor" } } ], "specularF0": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", "type": "Float", @@ -274,28 +274,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_specularF0Factor" + "name": "m_specularF0Factor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface reflectance.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_specularF0Map" + "name": "m_specularF0Map" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Specular reflection map UV set", "type": "Enum", @@ -303,41 +303,41 @@ "defaultValue": "Unwrapped", "connection": { "type": "ShaderInput", - "id": "m_specularF0MapUvIndex" + "name": "m_specularF0MapUvIndex" } }, // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR { - "id": "enableMultiScatterCompensation", + "name": "enableMultiScatterCompensation", "displayName": "Multiscattering Compensation", "description": "Whether to enable multiple scattering compensation.", "type": "Bool", "connection": { "type": "ShaderOption", - "id": "o_specularF0_enableMultiScatterCompensation" + "name": "o_specularF0_enableMultiScatterCompensation" } } ], "normal": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface normal direction.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_normalMap" + "name": "m_normalMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just rely on vertex normals.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Normal map UV set", "type": "Enum", @@ -345,33 +345,33 @@ "defaultValue": "Unwrapped", "connection": { "type": "ShaderInput", - "id": "m_normalMapUvIndex" + "name": "m_normalMapUvIndex" } }, { - "id": "flipX", + "name": "flipX", "displayName": "Flip X Channel", "description": "Flip tangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_flipNormalX" + "name": "m_flipNormalX" } }, { - "id": "flipY", + "name": "flipY", "displayName": "Flip Y Channel", "description": "Flip bitangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_flipNormalY" + "name": "m_flipNormalY" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the values", "type": "Float", @@ -380,30 +380,30 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_normalFactor" + "name": "m_normalFactor" } } ], "occlusion": [ { - "id": "diffuseTextureMap", + "name": "diffuseTextureMap", "displayName": "Diffuse AO", "description": "Texture for defining occlusion area for diffuse ambient lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_diffuseOcclusionMap" + "name": "m_diffuseOcclusionMap" } }, { - "id": "diffuseUseTexture", + "name": "diffuseUseTexture", "displayName": " Use Texture", "description": "Whether to use the Diffuse AO map.", "type": "Bool", "defaultValue": true }, { - "id": "diffuseTextureMapUv", + "name": "diffuseTextureMapUv", "displayName": " UV", "description": "Diffuse AO map UV set.", "type": "Enum", @@ -411,11 +411,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_diffuseOcclusionMapUvIndex" + "name": "m_diffuseOcclusionMapUvIndex" } }, { - "id": "diffuseFactor", + "name": "diffuseFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Diffuse AO", "type": "Float", @@ -424,28 +424,28 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_diffuseOcclusionFactor" + "name": "m_diffuseOcclusionFactor" } }, { - "id": "specularTextureMap", + "name": "specularTextureMap", "displayName": "Specular Cavity", "description": "Texture for defining occlusion area for specular lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_specularOcclusionMap" + "name": "m_specularOcclusionMap" } }, { - "id": "specularUseTexture", + "name": "specularUseTexture", "displayName": " Use Texture", "description": "Whether to use the Specular Cavity map.", "type": "Bool", "defaultValue": true }, { - "id": "specularTextureMapUv", + "name": "specularTextureMapUv", "displayName": " UV", "description": "Specular Cavity map UV set.", "type": "Enum", @@ -453,11 +453,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_specularOcclusionMapUvIndex" + "name": "m_specularOcclusionMapUvIndex" } }, { - "id": "specularFactor", + "name": "specularFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Specular Cavity", "type": "Float", @@ -466,24 +466,24 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_specularOcclusionFactor" + "name": "m_specularOcclusionFactor" } } ], "subsurfaceScattering": [ { - "id": "enableSubsurfaceScattering", + "name": "enableSubsurfaceScattering", "displayName": "Subsurface Scattering", "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_enableSubsurfaceScattering" + "name": "o_enableSubsurfaceScattering" } }, { - "id": "subsurfaceScatterFactor", + "name": "subsurfaceScatterFactor", "displayName": " Factor", "description": "Strength factor for scaling percentage of subsurface scattering effect applied", "type": "float", @@ -492,28 +492,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_subsurfaceScatteringFactor" + "name": "m_subsurfaceScatteringFactor" } }, { - "id": "influenceMap", + "name": "influenceMap", "displayName": " Influence Map", "description": "Texture for controlling the strength of subsurface scattering", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_subsurfaceScatteringInfluenceMap" + "name": "m_subsurfaceScatteringInfluenceMap" } }, { - "id": "useInfluenceMap", + "name": "useInfluenceMap", "displayName": " Use Influence Map", "description": "Whether to use the influence map.", "type": "Bool", "defaultValue": true }, { - "id": "influenceMapUv", + "name": "influenceMapUv", "displayName": " UV", "description": "Influence map UV set", "type": "Enum", @@ -521,18 +521,18 @@ "defaultValue": "Unwrapped", "connection": { "type": "ShaderInput", - "id": "m_subsurfaceScatteringInfluenceMapUvIndex" + "name": "m_subsurfaceScatteringInfluenceMapUvIndex" } }, { - "id": "scatterColor", + "name": "scatterColor", "displayName": " Scatter color", "description": "Color of volume light traveled through", "type": "Color", "defaultValue": [ 1.0, 0.27, 0.13 ] }, { - "id": "scatterDistance", + "name": "scatterDistance", "displayName": " Scatter distance", "description": "How far light traveled inside the volume", "type": "float", @@ -541,7 +541,7 @@ "softMax": 20.0 }, { - "id": "quality", + "name": "quality", "displayName": " Quality", "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel", "type": "float", @@ -550,11 +550,11 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_subsurfaceScatteringQuality" + "name": "m_subsurfaceScatteringQuality" } }, { - "id": "transmissionMode", + "name": "transmissionMode", "displayName": "Transmission", "description": "Algorithm used for calculating transmission", "type": "Enum", @@ -562,11 +562,11 @@ "defaultValue": "None", "connection": { "type": "ShaderOption", - "id": "o_transmission_mode" + "name": "o_transmission_mode" } }, { - "id": "thickness", + "name": "thickness", "displayName": " Thickness", "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel", "type": "float", @@ -575,24 +575,24 @@ "max": 1.0 }, { - "id": "thicknessMap", + "name": "thicknessMap", "displayName": " Thickness Map", "description": "Texture for controlling per pixel thickness", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_transmissionThicknessMap" + "name": "m_transmissionThicknessMap" } }, { - "id": "useThicknessMap", + "name": "useThicknessMap", "displayName": " Use Thickness Map", "description": "Whether to use the thickness map", "type": "Bool", "defaultValue": true }, { - "id": "thicknessMapUv", + "name": "thicknessMapUv", "displayName": " UV", "description": "Thickness map UV set", "type": "Enum", @@ -600,18 +600,18 @@ "defaultValue": "Unwrapped", "connection": { "type": "ShaderInput", - "id": "m_transmissionThicknessMapUvIndex" + "name": "m_transmissionThicknessMapUvIndex" } }, { - "id": "transmissionTint", + "name": "transmissionTint", "displayName": " Transmission Tint", "description": "Color of the volume light traveling through", "type": "Color", "defaultValue": [ 1.0, 0.8, 0.6 ] }, { - "id": "transmissionPower", + "name": "transmissionPower", "displayName": " Power", "description": "How much transmitted light scatter radially ", "type": "float", @@ -620,7 +620,7 @@ "softMax": 20.0 }, { - "id": "transmissionDistortion", + "name": "transmissionDistortion", "displayName": " Distortion", "description": "How much light direction distorted towards surface normal", "type": "float", @@ -629,7 +629,7 @@ "max": 1.0 }, { - "id": "transmissionAttenuation", + "name": "transmissionAttenuation", "displayName": " Attenuation", "description": "How fast transmitted light fade with thickness", "type": "float", @@ -638,7 +638,7 @@ "softMax": 20.0 }, { - "id": "transmissionScale", + "name": "transmissionScale", "displayName": " Scale", "description": "Strength of transmission", "type": "float", @@ -649,14 +649,14 @@ ], "wrinkleLayers": [ { - "id": "enable", + "name": "enable", "displayName": "Enable Wrinkle Layers", "description": "Enable wrinkle layers for morph animations, using vertex color blend weights.", "type": "Bool", "defaultValue": false }, { - "id": "count", + "name": "count", "displayName": "Number Of Layers", "description": "The number of wrinkle map layers to use. The blend values come from the 'COLOR0' vertex stream, where R/G/B/A correspond to wrinkle layers 1/2/3/4 respectively.", "type": "UInt", @@ -665,109 +665,109 @@ "max": 4 }, { - "id": "showBlendValues", + "name": "showBlendValues", "displayName": "Show Blend Values", "description": "Enable a debug mode that draws the blend values as red, green, blue, and white overlays.", "type": "Bool", "defaultValue": false }, { - "id": "enableBaseColor", + "name": "enableBaseColor", "displayName": "Enable Base Color Maps", "description": "Enable support for blending the base color according to morph animations.", "type": "Bool", "defaultValue": false }, { - "id": "baseColorMap1", + "name": "baseColorMap1", "displayName": " Base Color 1", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_wrinkle_baseColor_texture1" + "name": "m_wrinkle_baseColor_texture1" } }, { - "id": "baseColorMap2", + "name": "baseColorMap2", "displayName": " Base Color 2", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_wrinkle_baseColor_texture2" + "name": "m_wrinkle_baseColor_texture2" } }, { - "id": "baseColorMap3", + "name": "baseColorMap3", "displayName": " Base Color 3", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_wrinkle_baseColor_texture3" + "name": "m_wrinkle_baseColor_texture3" } }, { - "id": "baseColorMap4", + "name": "baseColorMap4", "displayName": " Base Color 4", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_wrinkle_baseColor_texture4" + "name": "m_wrinkle_baseColor_texture4" } }, { - "id": "enableNormal", + "name": "enableNormal", "displayName": "Enable Normal Maps", "description": "Enable support for blending the normal maps according to morph animations.", "type": "Bool", "defaultValue": false }, { - "id": "normalMap1", + "name": "normalMap1", "displayName": " Normals 1", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_wrinkle_normal_texture1" + "name": "m_wrinkle_normal_texture1" } }, { - "id": "normalMap2", + "name": "normalMap2", "displayName": " Normals 2", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_wrinkle_normal_texture2" + "name": "m_wrinkle_normal_texture2" } }, { - "id": "normalMap3", + "name": "normalMap3", "displayName": " Normals 3", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_wrinkle_normal_texture3" + "name": "m_wrinkle_normal_texture3" } }, { - "id": "normalMap4", + "name": "normalMap4", "displayName": " Normals 4", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_wrinkle_normal_texture4" + "name": "m_wrinkle_normal_texture4" } } ], "detailLayerGroup": [ { - "id": "enableDetailLayer", + "name": "enableDetailLayer", "displayName": "Enable Detail Layer", "description": "Enable detail layer for fine details and scratches", "type": "Bool", "defaultValue": false }, { - "id": "blendDetailFactor", + "name": "blendDetailFactor", "displayName": "Blend Factor", "description": "Scales the overall impact of the detail layer.", "type": "Float", @@ -776,28 +776,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_detail_blendFactor" + "name": "m_detail_blendFactor" } }, { - "id": "blendDetailMask", + "name": "blendDetailMask", "displayName": "Blend Mask", "description": "Detailed blend mask for application of the detail maps.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_detail_blendMask_texture" + "name": "m_detail_blendMask_texture" } }, { - "id": "enableDetailMaskTexture", + "name": "enableDetailMaskTexture", "displayName": " Use Texture", "description": "Enable detail blend mask", "type": "Bool", "defaultValue": true }, { - "id": "blendDetailMaskUv", + "name": "blendDetailMaskUv", "displayName": " Blend Mask UV", "description": "Which UV set to use for sampling the detail blend mask", "type": "Enum", @@ -805,11 +805,11 @@ "defaultValue": "Unwrapped", "connection": { "type": "ShaderInput", - "id": "m_detail_blendMask_uvIndex" + "name": "m_detail_blendMask_uvIndex" } }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "Detail Map UVs", "description": "Which UV set to use for detail map sampling", "type": "Enum", @@ -817,28 +817,28 @@ "defaultValue": "Unwrapped", "connection": { "type": "ShaderInput", - "id": "m_detail_allMapsUvIndex" + "name": "m_detail_allMapsUvIndex" } }, { - "id": "enableBaseColor", + "name": "enableBaseColor", "displayName": "Enable Base Color", "description": "Enable detail blending for base color", "type": "Bool", "defaultValue": false }, { - "id": "baseColorDetailMap", + "name": "baseColorDetailMap", "displayName": " Texture", "description": "Detailed Base Color Texture", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_detail_baseColor_texture" + "name": "m_detail_baseColor_texture" } }, { - "id": "baseColorDetailBlend", + "name": "baseColorDetailBlend", "displayName": " Blend Factor", "description": "How much to blend the detail layer into the base color.", "type": "Float", @@ -847,18 +847,18 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_detail_baseColor_factor" + "name": "m_detail_baseColor_factor" } }, { - "id": "enableNormals", + "name": "enableNormals", "displayName": "Enable Normal", "description": "Enable detail normal map to be used for fine detail normal such as scratches and small dents", "type": "Bool", "defaultValue": false }, { - "id": "normalDetailStrength", + "name": "normalDetailStrength", "displayName": " Factor", "description": "Strength factor for scaling the Detail Normal", "type": "Float", @@ -867,45 +867,45 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_detail_normal_factor" + "name": "m_detail_normal_factor" } }, { - "id": "normalDetailMap", + "name": "normalDetailMap", "displayName": " Texture", "description": "Detailed Normal map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_detail_normal_texture" + "name": "m_detail_normal_texture" } }, { - "id": "normalDetailFlipX", + "name": "normalDetailFlipX", "displayName": " Flip X Channel", "description": "Flip Detail tangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_detail_normal_flipX" + "name": "m_detail_normal_flipX" } }, { - "id": "normalDetailFlipY", + "name": "normalDetailFlipY", "displayName": " Flip Y Channel", "description": "Flip Detail bitangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_detail_normal_flipY" + "name": "m_detail_normal_flipY" } } ], "detailUV": [ { - "id": "center", + "name": "center", "displayName": "Center", "description": "Center point for scaling and rotation transformations.", "type": "vector2", @@ -913,7 +913,7 @@ "defaultValue": [ 0.5, 0.5 ] }, { - "id": "tileU", + "name": "tileU", "displayName": "Tile U", "description": "Scales texture coordinates in V.", "type": "float", @@ -921,7 +921,7 @@ "step": 0.1 }, { - "id": "tileV", + "name": "tileV", "displayName": "Tile V", "description": "Scales texture coordinates in V.", "type": "float", @@ -929,7 +929,7 @@ "step": 0.1 }, { - "id": "offsetU", + "name": "offsetU", "displayName": "Offset U", "description": "Offsets texture coordinates in the U direction.", "type": "float", @@ -938,7 +938,7 @@ "max": 1.0 }, { - "id": "offsetV", + "name": "offsetV", "displayName": "Offset V", "description": "Offsets texture coordinates in the V direction.", "type": "float", @@ -947,7 +947,7 @@ "max": 1.0 }, { - "id": "rotateDegrees", + "name": "rotateDegrees", "displayName": "Rotate", "description": "Rotates the texture coordinates (degrees).", "type": "float", @@ -957,7 +957,7 @@ "step": 1.0 }, { - "id": "scale", + "name": "scale", "displayName": "Scale", "description": "Scales texture coordinates in both U and V.", "type": "float", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype index bccb530eb4..5fa0dcb217 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype @@ -4,28 +4,28 @@ "version": 3, "groups": [ { - "id": "blend", + "name": "blend", "displayName": "Blend Settings", "description": "Properties for configuring how layers are blended together." }, { - "id": "parallax", + "name": "parallax", "displayName": "Parallax Settings", "description": "Properties for configuring the parallax effect, applied to all layers." }, { - "id": "uv", + "name": "uv", "displayName": "UVs", "description": "Properties for configuring UV transforms for the entire material, including the blend masks." }, { // Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader - "id": "irradiance", + "name": "irradiance", "displayName": "Irradiance", "description": "Properties for configuring the irradiance used in global illumination." }, { - "id": "general", + "name": "general", "displayName": "General Settings", "description": "General settings." }, @@ -33,52 +33,52 @@ // Layer 1 Groups //############################################################################################## { - "id": "layer1_baseColor", + "name": "layer1_baseColor", "displayName": "Layer 1: Base Color", "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." }, { - "id": "layer1_metallic", + "name": "layer1_metallic", "displayName": "Layer 1: Metallic", "description": "Properties for configuring whether the surface is metallic or not." }, { - "id": "layer1_roughness", + "name": "layer1_roughness", "displayName": "Layer 1: Roughness", "description": "Properties for configuring how rough the surface appears." }, { - "id": "layer1_specularF0", + "name": "layer1_specularF0", "displayName": "Layer 1: Specular Reflectance f0", "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." }, { - "id": "layer1_normal", + "name": "layer1_normal", "displayName": "Layer 1: Normal", "description": "Properties related to configuring surface normal." }, { - "id": "layer1_occlusion", + "name": "layer1_occlusion", "displayName": "Layer 1: Occlusion", "description": "Properties for baked textures for diffuse and specular occlusion of ambient lighting." }, { - "id": "layer1_emissive", + "name": "layer1_emissive", "displayName": "Layer 1: Emissive", "description": "Properties to add light emission, independent of other lights in the scene." }, { - "id": "layer1_clearCoat", + "name": "layer1_clearCoat", "displayName": "Layer 1: Clear Coat", "description": "Properties for configuring gloss clear coat" }, { - "id": "layer1_parallax", + "name": "layer1_parallax", "displayName": "Layer 1: Displacement", "description": "Properties for surface displacement, which can be used for displacement-based blending and/or a parallax effect." }, { - "id": "layer1_uv", + "name": "layer1_uv", "displayName": "Layer 1: UVs", "description": "Properties for configuring UV transforms." }, @@ -86,52 +86,52 @@ // Layer 2 Groups //############################################################################################## { - "id": "layer2_baseColor", + "name": "layer2_baseColor", "displayName": "Layer 2: Base Color", "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." }, { - "id": "layer2_metallic", + "name": "layer2_metallic", "displayName": "Layer 2: Metallic", "description": "Properties for configuring whether the surface is metallic or not." }, { - "id": "layer2_roughness", + "name": "layer2_roughness", "displayName": "Layer 2: Roughness", "description": "Properties for configuring how rough the surface appears." }, { - "id": "layer2_specularF0", + "name": "layer2_specularF0", "displayName": "Layer 2: Specular Reflectance f0", "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." }, { - "id": "layer2_normal", + "name": "layer2_normal", "displayName": "Layer 2: Normal", "description": "Properties related to configuring surface normal." }, { - "id": "layer2_occlusion", + "name": "layer2_occlusion", "displayName": "Layer 2: Occlusion", "description": "Properties for baked textures for diffuse and specular occlusion of ambient lighting." }, { - "id": "layer2_emissive", + "name": "layer2_emissive", "displayName": "Layer 2: Emissive", "description": "Properties to add light emission, independent of other lights in the scene." }, { - "id": "layer2_clearCoat", + "name": "layer2_clearCoat", "displayName": "Layer 2: Clear Coat", "description": "Properties for configuring gloss clear coat" }, { - "id": "layer2_parallax", + "name": "layer2_parallax", "displayName": "Layer 2: Displacement", "description": "Properties for surface displacement, which can be used for displacement-based blending and/or a parallax effect." }, { - "id": "layer2_uv", + "name": "layer2_uv", "displayName": "Layer 2: UVs", "description": "Properties for configuring UV transforms." }, @@ -139,52 +139,52 @@ // Layer 3 Groups //############################################################################################## { - "id": "layer3_baseColor", + "name": "layer3_baseColor", "displayName": "Layer 3: Base Color", "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." }, { - "id": "layer3_metallic", + "name": "layer3_metallic", "displayName": "Layer 3: Metallic", "description": "Properties for configuring whether the surface is metallic or not." }, { - "id": "layer3_roughness", + "name": "layer3_roughness", "displayName": "Layer 3: Roughness", "description": "Properties for configuring how rough the surface appears." }, { - "id": "layer3_specularF0", + "name": "layer3_specularF0", "displayName": "Layer 3: Specular Reflectance f0", "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." }, { - "id": "layer3_normal", + "name": "layer3_normal", "displayName": "Layer 3: Normal", "description": "Properties related to configuring surface normal." }, { - "id": "layer3_occlusion", + "name": "layer3_occlusion", "displayName": "Layer 3: Occlusion", "description": "Properties for baked textures for diffuse and specular occlusion of ambient lighting." }, { - "id": "layer3_emissive", + "name": "layer3_emissive", "displayName": "Layer 3: Emissive", "description": "Properties to add light emission, independent of other lights in the scene." }, { - "id": "layer3_clearCoat", + "name": "layer3_clearCoat", "displayName": "Layer 3: Clear Coat", "description": "Properties for configuring gloss clear coat" }, { - "id": "layer3_parallax", + "name": "layer3_parallax", "displayName": "Layer 3: Displacement", "description": "Properties for surface displacement, which can be used for displacement-based blending and/or a parallax effect." }, { - "id": "layer3_uv", + "name": "layer3_uv", "displayName": "Layer 3: UVs", "description": "Properties for configuring UV transforms." } @@ -195,118 +195,118 @@ //############################################################################################## "general": [ { - "id": "applySpecularAA", + "name": "applySpecularAA", "displayName": "Apply Specular AA", "description": "Whether to apply specular anti-aliasing in the shader.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_applySpecularAA" + "name": "o_applySpecularAA" } }, { - "id": "enableMultiScatterCompensation", + "name": "enableMultiScatterCompensation", "displayName": "Multiscattering Compensation", "description": "Whether to enable multiple scattering compensation.", "type": "Bool", "connection": { "type": "ShaderOption", - "id": "o_specularF0_enableMultiScatterCompensation" + "name": "o_specularF0_enableMultiScatterCompensation" } }, { - "id": "enableShadows", + "name": "enableShadows", "displayName": "Enable Shadows", "description": "Whether to use the shadow maps.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableShadows" + "name": "o_enableShadows" } }, { - "id": "enableDirectionalLights", + "name": "enableDirectionalLights", "displayName": "Enable Directional Lights", "description": "Whether to use directional lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableDirectionalLights" + "name": "o_enableDirectionalLights" } }, { - "id": "enablePunctualLights", + "name": "enablePunctualLights", "displayName": "Enable Punctual Lights", "description": "Whether to use punctual lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enablePunctualLights" + "name": "o_enablePunctualLights" } }, { - "id": "enableAreaLights", + "name": "enableAreaLights", "displayName": "Enable Area Lights", "description": "Whether to use area lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableAreaLights" + "name": "o_enableAreaLights" } }, { - "id": "enableIBL", + "name": "enableIBL", "displayName": "Enable IBL", "description": "Whether to use Image Based Lighting (IBL).", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableIBL" + "name": "o_enableIBL" } }, { - "id": "forwardPassIBLSpecular", + "name": "forwardPassIBLSpecular", "displayName": "Forward Pass IBL Specular", "description": "Whether to apply IBL specular in the forward pass.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_materialUseForwardPassIBLSpecular" + "name": "o_materialUseForwardPassIBLSpecular" } } ], "blend": [ { - "id": "enableLayer2", + "name": "enableLayer2", "displayName": "Enable Layer 2", "description": "Whether to enable layer 2.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_layer2_enabled" + "name": "o_layer2_enabled" } }, { - "id": "enableLayer3", + "name": "enableLayer3", "displayName": "Enable Layer 3", "description": "Whether to enable layer 3.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_layer3_enabled" + "name": "o_layer3_enabled" } }, { - "id": "blendSource", + "name": "blendSource", "displayName": "Blend Source", "description": "The source to use for defining the blend mask. Note VertexColors mode will still use the texture as a fallback if the mesh does not have a COLOR0 stream.", "type": "Enum", @@ -314,22 +314,22 @@ "defaultValue": "BlendMaskTexture", "connection": { "type": "ShaderOption", - "id": "o_layerBlendSource" + "name": "o_layerBlendSource" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Blend Mask Texture", "description": "RGB image where each channel is the blend mask for one of the three available layers.", "type": "Image", "defaultValue": "Textures/DefaultBlendMask_layers.png", "connection": { "type": "ShaderInput", - "id": "m_blendMaskTexture" + "name": "m_blendMaskTexture" } }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "Blend Mask UV", "description": "Blend Mask UV set.", "type": "Enum", @@ -337,11 +337,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_blendMaskUvIndex" + "name": "m_blendMaskUvIndex" } }, { - "id": "displacementBlendDistance", + "name": "displacementBlendDistance", "displayName": "Blend Distance", "description": "Adjusts how smoothly to transition between layers when displacement blending is enabled.", "type": "Float", @@ -351,11 +351,11 @@ "step": 0.001, "connection": { "type": "ShaderInput", - "id": "m_displacementBlendDistance" + "name": "m_displacementBlendDistance" } }, { - "id": "debugDrawMode", + "name": "debugDrawMode", "displayName": "Debug Draw Mode", "description": "Enables various debug view features.", "type": "Enum", @@ -363,7 +363,7 @@ "defaultValue": "None", "connection": { "type": "ShaderOption", - "id": "o_debugDrawMode" + "name": "o_debugDrawMode" } } ], @@ -372,14 +372,14 @@ // Note parallax is enabled by default so that as soon as a user hooks up displacement settings they will see some parallax applied. // The functor that controls parallax will set o_parallax_feature_enabled=false when all the individual layers have no displacement, so // a default value of true here will not have any initial impact on performance. - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Whether to enable the parallax feature for this material.", "type": "Bool", "defaultValue": true }, { - "id": "parallaxUv", + "name": "parallaxUv", "displayName": "UV", "description": "UV set that supports parallax mapping.", "type": "Enum", @@ -387,11 +387,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_parallaxUvIndex" + "name": "m_parallaxUvIndex" } }, { - "id": "algorithm", + "name": "algorithm", "displayName": "Algorithm", "description": "Select the algorithm to use for parallax mapping.", "type": "Enum", @@ -399,11 +399,11 @@ "defaultValue": "POM", "connection": { "type": "ShaderOption", - "id": "o_parallax_algorithm" + "name": "o_parallax_algorithm" } }, { - "id": "quality", + "name": "quality", "displayName": "Quality", "description": "Quality of parallax mapping.", "type": "Enum", @@ -411,35 +411,35 @@ "defaultValue": "Low", "connection": { "type": "ShaderOption", - "id": "o_parallax_quality" + "name": "o_parallax_quality" } }, { - "id": "pdo", + "name": "pdo", "displayName": "Pixel Depth Offset", "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_parallax_enablePixelDepthOffset" + "name": "o_parallax_enablePixelDepthOffset" } }, { - "id": "showClipping", + "name": "showClipping", "displayName": "Show Clipping", "description": "Highlight areas where the height map is clipped by the mesh surface.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_parallax_highlightClipping" + "name": "o_parallax_highlightClipping" } } ], "uv": [ { - "id": "center", + "name": "center", "displayName": "Center", "description": "Center point for scaling and rotation transformations.", "type": "vector2", @@ -447,7 +447,7 @@ "defaultValue": [ 0.5, 0.5 ] }, { - "id": "tileU", + "name": "tileU", "displayName": "Tile U", "description": "Scales texture coordinates in V.", "type": "float", @@ -455,7 +455,7 @@ "step": 0.1 }, { - "id": "tileV", + "name": "tileV", "displayName": "Tile V", "description": "Scales texture coordinates in V.", "type": "float", @@ -463,7 +463,7 @@ "step": 0.1 }, { - "id": "offsetU", + "name": "offsetU", "displayName": "Offset U", "description": "Offsets texture coordinates in the U direction.", "type": "float", @@ -473,7 +473,7 @@ "step": 0.001 }, { - "id": "offsetV", + "name": "offsetV", "displayName": "Offset V", "description": "Offsets texture coordinates in the V direction.", "type": "float", @@ -483,7 +483,7 @@ "step": 0.001 }, { - "id": "rotateDegrees", + "name": "rotateDegrees", "displayName": "Rotate", "description": "Rotates the texture coordinates (degrees).", "type": "float", @@ -493,7 +493,7 @@ "step": 1.0 }, { - "id": "scale", + "name": "scale", "displayName": "Scale", "description": "Scales texture coordinates in both U and V.", "type": "float", @@ -504,14 +504,14 @@ "irradiance": [ // Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ] }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", "type": "Float", @@ -525,18 +525,18 @@ //############################################################################################## "layer1_baseColor": [ { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_layer1_m_baseColor" + "name": "m_layer1_m_baseColor" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", "type": "Float", @@ -545,28 +545,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_baseColorFactor" + "name": "m_layer1_m_baseColorFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Base color texture map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_baseColorMap" + "name": "m_layer1_m_baseColorMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Base color map UV set", "type": "Enum", @@ -574,11 +574,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_baseColorMapUvIndex" + "name": "m_layer1_m_baseColorMapUvIndex" } }, { - "id": "textureBlendMode", + "name": "textureBlendMode", "displayName": "Texture Blend Mode", "description": "Selects the equation to use when combining Color, Factor, and Texture.", "type": "Enum", @@ -586,13 +586,13 @@ "defaultValue": "Multiply", "connection": { "type": "ShaderOption", - "id": "o_layer1_o_baseColorTextureBlendMode" + "name": "o_layer1_o_baseColorTextureBlendMode" } } ], "layer1_metallic": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "This value is linear, black is non-metal and white means raw metal.", "type": "Float", @@ -601,28 +601,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_metallicFactor" + "name": "m_layer1_m_metallicFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_metallicMap" + "name": "m_layer1_m_metallicMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Metallic map UV set", "type": "Enum", @@ -630,30 +630,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_metallicMapUvIndex" + "name": "m_layer1_m_metallicMapUvIndex" } } ], "layer1_roughness": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface roughness.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_roughnessMap" + "name": "m_layer1_m_roughnessMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Roughness map UV set", "type": "Enum", @@ -661,12 +661,12 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_roughnessMapUvIndex" + "name": "m_layer1_m_roughnessMapUvIndex" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "lowerBound", + "name": "lowerBound", "displayName": "Lower Bound", "description": "The roughness value that corresponds to black in the texture.", "type": "Float", @@ -675,12 +675,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_roughnessLowerBound" + "name": "m_layer1_m_roughnessLowerBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "upperBound", + "name": "upperBound", "displayName": "Upper Bound", "description": "The roughness value that corresponds to white in the texture.", "type": "Float", @@ -689,12 +689,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_roughnessUpperBound" + "name": "m_layer1_m_roughnessUpperBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Controls the roughness value", "type": "Float", @@ -703,13 +703,13 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_roughnessFactor" + "name": "m_layer1_m_roughnessFactor" } } ], "layer1_specularF0": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", "type": "Float", @@ -718,28 +718,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_specularF0Factor" + "name": "m_layer1_m_specularF0Factor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface reflectance.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_specularF0Map" + "name": "m_layer1_m_specularF0Map" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Specular reflection map UV set", "type": "Enum", @@ -747,30 +747,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_specularF0MapUvIndex" + "name": "m_layer1_m_specularF0MapUvIndex" } } ], "layer1_normal": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface normal direction.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_normalMap" + "name": "m_layer1_m_normalMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just rely on vertex normals.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Normal map UV set", "type": "Enum", @@ -778,33 +778,33 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_normalMapUvIndex" + "name": "m_layer1_m_normalMapUvIndex" } }, { - "id": "flipX", + "name": "flipX", "displayName": "Flip X Channel", "description": "Flip tangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_flipNormalX" + "name": "m_layer1_m_flipNormalX" } }, { - "id": "flipY", + "name": "flipY", "displayName": "Flip Y Channel", "description": "Flip bitangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_flipNormalY" + "name": "m_layer1_m_flipNormalY" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the values", "type": "Float", @@ -813,20 +813,20 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_normalFactor" + "name": "m_layer1_m_normalFactor" } } ], "layer1_clearCoat": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable clear coat", "type": "Bool", "defaultValue": false }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the percentage of effect applied", "type": "Float", @@ -835,28 +835,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_clearCoatFactor" + "name": "m_layer1_m_clearCoatFactor" } }, { - "id": "influenceMap", + "name": "influenceMap", "displayName": " Influence Map", "description": "Strength factor texture", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_clearCoatInfluenceMap" + "name": "m_layer1_m_clearCoatInfluenceMap" } }, { - "id": "useInfluenceMap", + "name": "useInfluenceMap", "displayName": " Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "influenceMapUv", + "name": "influenceMapUv", "displayName": " UV", "description": "Strength factor map UV set", "type": "Enum", @@ -864,11 +864,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_clearCoatInfluenceMapUvIndex" + "name": "m_layer1_m_clearCoatInfluenceMapUvIndex" } }, { - "id": "roughness", + "name": "roughness", "displayName": "Roughness", "description": "Clear coat layer roughness", "type": "Float", @@ -877,28 +877,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_clearCoatRoughness" + "name": "m_layer1_m_clearCoatRoughness" } }, { - "id": "roughnessMap", + "name": "roughnessMap", "displayName": " Roughness Map", "description": "Texture for defining surface roughness", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_clearCoatRoughnessMap" + "name": "m_layer1_m_clearCoatRoughnessMap" } }, { - "id": "useRoughnessMap", + "name": "useRoughnessMap", "displayName": " Use Texture", "description": "Whether to use the texture, or just default to the roughness value.", "type": "Bool", "defaultValue": true }, { - "id": "roughnessMapUv", + "name": "roughnessMapUv", "displayName": " UV", "description": "Roughness map UV set", "type": "Enum", @@ -906,11 +906,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_clearCoatRoughnessMapUvIndex" + "name": "m_layer1_m_clearCoatRoughnessMapUvIndex" } }, { - "id": "normalStrength", + "name": "normalStrength", "displayName": "Normal Strength", "description": "Scales the impact of the clear coat normal map", "type": "Float", @@ -919,28 +919,28 @@ "max": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_clearCoatNormalStrength" + "name": "m_layer1_m_clearCoatNormalStrength" } }, { - "id": "normalMap", + "name": "normalMap", "displayName": "Normal Map", "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_clearCoatNormalMap" + "name": "m_layer1_m_clearCoatNormalMap" } }, { - "id": "useNormalMap", + "name": "useNormalMap", "displayName": " Use Texture", "description": "Whether to use the normal map", "type": "Bool", "defaultValue": true }, { - "id": "normalMapUv", + "name": "normalMapUv", "displayName": " UV", "description": "Normal map UV set", "type": "Enum", @@ -948,30 +948,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_clearCoatNormalMapUvIndex" + "name": "m_layer1_m_clearCoatNormalMapUvIndex" } } ], "layer1_occlusion": [ { - "id": "diffuseTextureMap", + "name": "diffuseTextureMap", "displayName": "Diffuse AO", "description": "Texture for defining occlusion area for diffuse ambient lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_diffuseOcclusionMap" + "name": "m_layer1_m_diffuseOcclusionMap" } }, { - "id": "diffuseUseTexture", + "name": "diffuseUseTexture", "displayName": " Use Texture", "description": "Whether to use the Diffuse AO map.", "type": "Bool", "defaultValue": true }, { - "id": "diffuseTextureMapUv", + "name": "diffuseTextureMapUv", "displayName": " UV", "description": "Diffuse AO map UV set.", "type": "Enum", @@ -979,11 +979,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_diffuseOcclusionMapUvIndex" + "name": "m_layer1_m_diffuseOcclusionMapUvIndex" } }, { - "id": "diffuseFactor", + "name": "diffuseFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Diffuse AO", "type": "Float", @@ -992,28 +992,28 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_diffuseOcclusionFactor" + "name": "m_layer1_m_diffuseOcclusionFactor" } }, { - "id": "specularTextureMap", + "name": "specularTextureMap", "displayName": "Specular Cavity", "description": "Texture for defining occlusion area for specular lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_specularOcclusionMap" + "name": "m_layer1_m_specularOcclusionMap" } }, { - "id": "specularUseTexture", + "name": "specularUseTexture", "displayName": " Use Texture", "description": "Whether to use the Specular Cavity map.", "type": "Bool", "defaultValue": true }, { - "id": "specularTextureMapUv", + "name": "specularTextureMapUv", "displayName": " UV", "description": "Specular Cavity map UV set.", "type": "Enum", @@ -1021,11 +1021,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_specularOcclusionMapUvIndex" + "name": "m_layer1_m_specularOcclusionMapUvIndex" } }, { - "id": "specularFactor", + "name": "specularFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Specular Cavity", "type": "Float", @@ -1034,20 +1034,20 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_specularOcclusionFactor" + "name": "m_layer1_m_specularOcclusionFactor" } } ], "layer1_emissive": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable the emissive group", "type": "Bool", "defaultValue": false }, { - "id": "unit", + "name": "unit", "displayName": "Units", "description": "The photometric units of the Intensity property.", "type": "Enum", @@ -1055,18 +1055,18 @@ "defaultValue": "Ev100" }, { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_layer1_m_emissiveColor" + "name": "m_layer1_m_emissiveColor" } }, { - "id": "intensity", + "name": "intensity", "displayName": "Intensity", "description": "The amount of energy emitted.", "type": "Float", @@ -1077,24 +1077,24 @@ "softMax": 16 }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining emissive area.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_emissiveMap" + "name": "m_layer1_m_emissiveMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Emissive map UV set", "type": "Enum", @@ -1102,30 +1102,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_emissiveMapUvIndex" + "name": "m_layer1_m_emissiveMapUvIndex" } } ], "layer1_parallax": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Height Map", "description": "Displacement height map, which can be used for layer blending and/or a parallax effect.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer1_m_heightmap" + "name": "m_layer1_m_heightmap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the height map.", "type": "Bool", "defaultValue": true }, { - "id": "factor", + "name": "factor", "displayName": "Scale", "description": "The total height of the height map in local model units.", "type": "Float", @@ -1134,11 +1134,11 @@ "softMax": 0.1, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_heightmapScale" + "name": "m_layer1_m_heightmapScale" } }, { - "id": "offset", + "name": "offset", "displayName": "Offset", "description": "Adjusts the overall displacement amount in local model units.", "type": "Float", @@ -1147,13 +1147,13 @@ "softMax": 0.1, "connection": { "type": "ShaderInput", - "id": "m_layer1_m_heightmapOffset" + "name": "m_layer1_m_heightmapOffset" } } ], "layer1_uv": [ { - "id": "center", + "name": "center", "displayName": "Center", "description": "Center point for scaling and rotation transformations.", "type": "vector2", @@ -1161,7 +1161,7 @@ "defaultValue": [ 0.5, 0.5 ] }, { - "id": "tileU", + "name": "tileU", "displayName": "Tile U", "description": "Scales texture coordinates in V.", "type": "float", @@ -1169,7 +1169,7 @@ "step": 0.1 }, { - "id": "tileV", + "name": "tileV", "displayName": "Tile V", "description": "Scales texture coordinates in V.", "type": "float", @@ -1177,7 +1177,7 @@ "step": 0.1 }, { - "id": "offsetU", + "name": "offsetU", "displayName": "Offset U", "description": "Offsets texture coordinates in the U direction.", "type": "float", @@ -1187,7 +1187,7 @@ "step": 0.001 }, { - "id": "offsetV", + "name": "offsetV", "displayName": "Offset V", "description": "Offsets texture coordinates in the V direction.", "type": "float", @@ -1197,7 +1197,7 @@ "step": 0.001 }, { - "id": "rotateDegrees", + "name": "rotateDegrees", "displayName": "Rotate", "description": "Rotates the texture coordinates (degrees).", "type": "float", @@ -1207,7 +1207,7 @@ "step": 1.0 }, { - "id": "scale", + "name": "scale", "displayName": "Scale", "description": "Scales texture coordinates in both U and V.", "type": "float", @@ -1220,18 +1220,18 @@ //############################################################################################## "layer2_baseColor": [ { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_layer2_m_baseColor" + "name": "m_layer2_m_baseColor" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", "type": "Float", @@ -1240,28 +1240,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_baseColorFactor" + "name": "m_layer2_m_baseColorFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Base color texture map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_baseColorMap" + "name": "m_layer2_m_baseColorMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Base color map UV set", "type": "Enum", @@ -1269,11 +1269,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_baseColorMapUvIndex" + "name": "m_layer2_m_baseColorMapUvIndex" } }, { - "id": "textureBlendMode", + "name": "textureBlendMode", "displayName": "Texture Blend Mode", "description": "Selects the equation to use when combining Color, Factor, and Texture.", "type": "Enum", @@ -1281,13 +1281,13 @@ "defaultValue": "Multiply", "connection": { "type": "ShaderOption", - "id": "o_layer2_o_baseColorTextureBlendMode" + "name": "o_layer2_o_baseColorTextureBlendMode" } } ], "layer2_metallic": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "This value is linear, black is non-metal and white means raw metal.", "type": "Float", @@ -1296,28 +1296,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_metallicFactor" + "name": "m_layer2_m_metallicFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_metallicMap" + "name": "m_layer2_m_metallicMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Metallic map UV set", "type": "Enum", @@ -1325,30 +1325,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_metallicMapUvIndex" + "name": "m_layer2_m_metallicMapUvIndex" } } ], "layer2_roughness": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface roughness.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_roughnessMap" + "name": "m_layer2_m_roughnessMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Roughness map UV set", "type": "Enum", @@ -1356,12 +1356,12 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_roughnessMapUvIndex" + "name": "m_layer2_m_roughnessMapUvIndex" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "lowerBound", + "name": "lowerBound", "displayName": "Lower Bound", "description": "The roughness value that corresponds to black in the texture.", "type": "Float", @@ -1370,12 +1370,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_roughnessLowerBound" + "name": "m_layer2_m_roughnessLowerBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "upperBound", + "name": "upperBound", "displayName": "Upper Bound", "description": "The roughness value that corresponds to white in the texture.", "type": "Float", @@ -1384,12 +1384,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_roughnessUpperBound" + "name": "m_layer2_m_roughnessUpperBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Controls the roughness value", "type": "Float", @@ -1398,13 +1398,13 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_roughnessFactor" + "name": "m_layer2_m_roughnessFactor" } } ], "layer2_specularF0": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", "type": "Float", @@ -1413,28 +1413,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_specularF0Factor" + "name": "m_layer2_m_specularF0Factor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface reflectance.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_specularF0Map" + "name": "m_layer2_m_specularF0Map" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Specular reflection map UV set", "type": "Enum", @@ -1442,30 +1442,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_specularF0MapUvIndex" + "name": "m_layer2_m_specularF0MapUvIndex" } } ], "layer2_normal": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface normal direction.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_normalMap" + "name": "m_layer2_m_normalMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just rely on vertex normals.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Normal map UV set", "type": "Enum", @@ -1473,33 +1473,33 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_normalMapUvIndex" + "name": "m_layer2_m_normalMapUvIndex" } }, { - "id": "flipX", + "name": "flipX", "displayName": "Flip X Channel", "description": "Flip tangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_flipNormalX" + "name": "m_layer2_m_flipNormalX" } }, { - "id": "flipY", + "name": "flipY", "displayName": "Flip Y Channel", "description": "Flip bitangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_flipNormalY" + "name": "m_layer2_m_flipNormalY" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the values", "type": "Float", @@ -1508,20 +1508,20 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_normalFactor" + "name": "m_layer2_m_normalFactor" } } ], "layer2_clearCoat": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable clear coat", "type": "Bool", "defaultValue": false }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the percentage of effect applied", "type": "Float", @@ -1530,28 +1530,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_clearCoatFactor" + "name": "m_layer2_m_clearCoatFactor" } }, { - "id": "influenceMap", + "name": "influenceMap", "displayName": " Influence Map", "description": "Strength factor texture", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_clearCoatInfluenceMap" + "name": "m_layer2_m_clearCoatInfluenceMap" } }, { - "id": "useInfluenceMap", + "name": "useInfluenceMap", "displayName": " Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "influenceMapUv", + "name": "influenceMapUv", "displayName": " UV", "description": "Strength factor map UV set", "type": "Enum", @@ -1559,11 +1559,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_clearCoatInfluenceMapUvIndex" + "name": "m_layer2_m_clearCoatInfluenceMapUvIndex" } }, { - "id": "roughness", + "name": "roughness", "displayName": "Roughness", "description": "Clear coat layer roughness", "type": "Float", @@ -1572,28 +1572,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_clearCoatRoughness" + "name": "m_layer2_m_clearCoatRoughness" } }, { - "id": "roughnessMap", + "name": "roughnessMap", "displayName": " Roughness Map", "description": "Texture for defining surface roughness", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_clearCoatRoughnessMap" + "name": "m_layer2_m_clearCoatRoughnessMap" } }, { - "id": "useRoughnessMap", + "name": "useRoughnessMap", "displayName": " Use Texture", "description": "Whether to use the texture, or just default to the roughness value.", "type": "Bool", "defaultValue": true }, { - "id": "roughnessMapUv", + "name": "roughnessMapUv", "displayName": " UV", "description": "Roughness map UV set", "type": "Enum", @@ -1601,11 +1601,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_clearCoatRoughnessMapUvIndex" + "name": "m_layer2_m_clearCoatRoughnessMapUvIndex" } }, { - "id": "normalStrength", + "name": "normalStrength", "displayName": "Normal Strength", "description": "Scales the impact of the clear coat normal map", "type": "Float", @@ -1614,28 +1614,28 @@ "max": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_clearCoatNormalStrength" + "name": "m_layer2_m_clearCoatNormalStrength" } }, { - "id": "normalMap", + "name": "normalMap", "displayName": "Normal Map", "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_clearCoatNormalMap" + "name": "m_layer2_m_clearCoatNormalMap" } }, { - "id": "useNormalMap", + "name": "useNormalMap", "displayName": " Use Texture", "description": "Whether to use the normal map", "type": "Bool", "defaultValue": true }, { - "id": "normalMapUv", + "name": "normalMapUv", "displayName": " UV", "description": "Normal map UV set", "type": "Enum", @@ -1643,30 +1643,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_clearCoatNormalMapUvIndex" + "name": "m_layer2_m_clearCoatNormalMapUvIndex" } } ], "layer2_occlusion": [ { - "id": "diffuseTextureMap", + "name": "diffuseTextureMap", "displayName": "Diffuse AO", "description": "Texture for defining occlusion area for diffuse ambient lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_diffuseOcclusionMap" + "name": "m_layer2_m_diffuseOcclusionMap" } }, { - "id": "diffuseUseTexture", + "name": "diffuseUseTexture", "displayName": " Use Texture", "description": "Whether to use the Diffuse AO map.", "type": "Bool", "defaultValue": true }, { - "id": "diffuseTextureMapUv", + "name": "diffuseTextureMapUv", "displayName": " UV", "description": "Diffuse AO map UV set.", "type": "Enum", @@ -1674,11 +1674,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_diffuseOcclusionMapUvIndex" + "name": "m_layer2_m_diffuseOcclusionMapUvIndex" } }, { - "id": "diffuseFactor", + "name": "diffuseFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Diffuse AO", "type": "Float", @@ -1687,28 +1687,28 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_diffuseOcclusionFactor" + "name": "m_layer2_m_diffuseOcclusionFactor" } }, { - "id": "specularTextureMap", + "name": "specularTextureMap", "displayName": "Specular Cavity", "description": "Texture for defining occlusion area for specular lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_specularOcclusionMap" + "name": "m_layer2_m_specularOcclusionMap" } }, { - "id": "specularUseTexture", + "name": "specularUseTexture", "displayName": " Use Texture", "description": "Whether to use the Specular Cavity map.", "type": "Bool", "defaultValue": true }, { - "id": "specularTextureMapUv", + "name": "specularTextureMapUv", "displayName": " UV", "description": "Specular Cavity map UV set.", "type": "Enum", @@ -1716,11 +1716,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_specularOcclusionMapUvIndex" + "name": "m_layer2_m_specularOcclusionMapUvIndex" } }, { - "id": "specularFactor", + "name": "specularFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Specular Cavity", "type": "Float", @@ -1729,20 +1729,20 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_specularOcclusionFactor" + "name": "m_layer2_m_specularOcclusionFactor" } } ], "layer2_emissive": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable the emissive group", "type": "Bool", "defaultValue": false }, { - "id": "unit", + "name": "unit", "displayName": "Units", "description": "The photometric units of the Intensity property.", "type": "Enum", @@ -1750,18 +1750,18 @@ "defaultValue": "Ev100" }, { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_layer2_m_emissiveColor" + "name": "m_layer2_m_emissiveColor" } }, { - "id": "intensity", + "name": "intensity", "displayName": "Intensity", "description": "The amount of energy emitted.", "type": "Float", @@ -1772,24 +1772,24 @@ "softMax": 16 }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining emissive area.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_emissiveMap" + "name": "m_layer2_m_emissiveMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Emissive map UV set", "type": "Enum", @@ -1797,30 +1797,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_emissiveMapUvIndex" + "name": "m_layer2_m_emissiveMapUvIndex" } } ], "layer2_parallax": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Height Map", "description": "Displacement height map, which can be used for layer blending and/or a parallax effect.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer2_m_heightmap" + "name": "m_layer2_m_heightmap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the height map.", "type": "Bool", "defaultValue": true }, { - "id": "factor", + "name": "factor", "displayName": "Scale", "description": "The total height of the height map in local model units.", "type": "Float", @@ -1829,11 +1829,11 @@ "softMax": 0.1, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_heightmapScale" + "name": "m_layer2_m_heightmapScale" } }, { - "id": "offset", + "name": "offset", "displayName": "Offset", "description": "Adjusts the overall displacement amount in local model units.", "type": "Float", @@ -1842,13 +1842,13 @@ "softMax": 0.1, "connection": { "type": "ShaderInput", - "id": "m_layer2_m_heightmapOffset" + "name": "m_layer2_m_heightmapOffset" } } ], "layer2_uv": [ { - "id": "center", + "name": "center", "displayName": "Center", "description": "Center point for scaling and rotation transformations.", "type": "vector2", @@ -1856,7 +1856,7 @@ "defaultValue": [ 0.5, 0.5 ] }, { - "id": "tileU", + "name": "tileU", "displayName": "Tile U", "description": "Scales texture coordinates in V.", "type": "float", @@ -1864,7 +1864,7 @@ "step": 0.1 }, { - "id": "tileV", + "name": "tileV", "displayName": "Tile V", "description": "Scales texture coordinates in V.", "type": "float", @@ -1872,7 +1872,7 @@ "step": 0.1 }, { - "id": "offsetU", + "name": "offsetU", "displayName": "Offset U", "description": "Offsets texture coordinates in the U direction.", "type": "float", @@ -1882,7 +1882,7 @@ "step": 0.001 }, { - "id": "offsetV", + "name": "offsetV", "displayName": "Offset V", "description": "Offsets texture coordinates in the V direction.", "type": "float", @@ -1892,7 +1892,7 @@ "step": 0.001 }, { - "id": "rotateDegrees", + "name": "rotateDegrees", "displayName": "Rotate", "description": "Rotates the texture coordinates (degrees).", "type": "float", @@ -1902,7 +1902,7 @@ "step": 1.0 }, { - "id": "scale", + "name": "scale", "displayName": "Scale", "description": "Scales texture coordinates in both U and V.", "type": "float", @@ -1915,18 +1915,18 @@ //############################################################################################## "layer3_baseColor": [ { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_layer3_m_baseColor" + "name": "m_layer3_m_baseColor" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", "type": "Float", @@ -1935,28 +1935,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_baseColorFactor" + "name": "m_layer3_m_baseColorFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Base color texture map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_baseColorMap" + "name": "m_layer3_m_baseColorMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Base color map UV set", "type": "Enum", @@ -1964,11 +1964,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_baseColorMapUvIndex" + "name": "m_layer3_m_baseColorMapUvIndex" } }, { - "id": "textureBlendMode", + "name": "textureBlendMode", "displayName": "Texture Blend Mode", "description": "Selects the equation to use when combining Color, Factor, and Texture.", "type": "Enum", @@ -1976,13 +1976,13 @@ "defaultValue": "Multiply", "connection": { "type": "ShaderOption", - "id": "o_layer3_o_baseColorTextureBlendMode" + "name": "o_layer3_o_baseColorTextureBlendMode" } } ], "layer3_metallic": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "This value is linear, black is non-metal and white means raw metal.", "type": "Float", @@ -1991,28 +1991,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_metallicFactor" + "name": "m_layer3_m_metallicFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_metallicMap" + "name": "m_layer3_m_metallicMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Metallic map UV set", "type": "Enum", @@ -2020,30 +2020,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_metallicMapUvIndex" + "name": "m_layer3_m_metallicMapUvIndex" } } ], "layer3_roughness": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface roughness.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_roughnessMap" + "name": "m_layer3_m_roughnessMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Roughness map UV set", "type": "Enum", @@ -2051,12 +2051,12 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_roughnessMapUvIndex" + "name": "m_layer3_m_roughnessMapUvIndex" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "lowerBound", + "name": "lowerBound", "displayName": "Lower Bound", "description": "The roughness value that corresponds to black in the texture.", "type": "Float", @@ -2065,12 +2065,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_roughnessLowerBound" + "name": "m_layer3_m_roughnessLowerBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "upperBound", + "name": "upperBound", "displayName": "Upper Bound", "description": "The roughness value that corresponds to white in the texture.", "type": "Float", @@ -2079,12 +2079,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_roughnessUpperBound" + "name": "m_layer3_m_roughnessUpperBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Controls the roughness value", "type": "Float", @@ -2093,13 +2093,13 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_roughnessFactor" + "name": "m_layer3_m_roughnessFactor" } } ], "layer3_specularF0": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", "type": "Float", @@ -2108,28 +2108,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_specularF0Factor" + "name": "m_layer3_m_specularF0Factor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface reflectance.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_specularF0Map" + "name": "m_layer3_m_specularF0Map" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Specular reflection map UV set", "type": "Enum", @@ -2137,30 +2137,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_specularF0MapUvIndex" + "name": "m_layer3_m_specularF0MapUvIndex" } } ], "layer3_normal": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface normal direction.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_normalMap" + "name": "m_layer3_m_normalMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just rely on vertex normals.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Normal map UV set", "type": "Enum", @@ -2168,33 +2168,33 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_normalMapUvIndex" + "name": "m_layer3_m_normalMapUvIndex" } }, { - "id": "flipX", + "name": "flipX", "displayName": "Flip X Channel", "description": "Flip tangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_flipNormalX" + "name": "m_layer3_m_flipNormalX" } }, { - "id": "flipY", + "name": "flipY", "displayName": "Flip Y Channel", "description": "Flip bitangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_flipNormalY" + "name": "m_layer3_m_flipNormalY" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the values", "type": "Float", @@ -2203,20 +2203,20 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_normalFactor" + "name": "m_layer3_m_normalFactor" } } ], "layer3_clearCoat": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable clear coat", "type": "Bool", "defaultValue": false }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the percentage of effect applied", "type": "Float", @@ -2225,28 +2225,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_clearCoatFactor" + "name": "m_layer3_m_clearCoatFactor" } }, { - "id": "influenceMap", + "name": "influenceMap", "displayName": " Influence Map", "description": "Strength factor texture", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_clearCoatInfluenceMap" + "name": "m_layer3_m_clearCoatInfluenceMap" } }, { - "id": "useInfluenceMap", + "name": "useInfluenceMap", "displayName": " Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "influenceMapUv", + "name": "influenceMapUv", "displayName": " UV", "description": "Strength factor map UV set", "type": "Enum", @@ -2254,11 +2254,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_clearCoatInfluenceMapUvIndex" + "name": "m_layer3_m_clearCoatInfluenceMapUvIndex" } }, { - "id": "roughness", + "name": "roughness", "displayName": "Roughness", "description": "Clear coat layer roughness", "type": "Float", @@ -2267,28 +2267,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_clearCoatRoughness" + "name": "m_layer3_m_clearCoatRoughness" } }, { - "id": "roughnessMap", + "name": "roughnessMap", "displayName": " Roughness Map", "description": "Texture for defining surface roughness", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_clearCoatRoughnessMap" + "name": "m_layer3_m_clearCoatRoughnessMap" } }, { - "id": "useRoughnessMap", + "name": "useRoughnessMap", "displayName": " Use Texture", "description": "Whether to use the texture, or just default to the roughness value.", "type": "Bool", "defaultValue": true }, { - "id": "roughnessMapUv", + "name": "roughnessMapUv", "displayName": " UV", "description": "Roughness map UV set", "type": "Enum", @@ -2296,11 +2296,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_clearCoatRoughnessMapUvIndex" + "name": "m_layer3_m_clearCoatRoughnessMapUvIndex" } }, { - "id": "normalStrength", + "name": "normalStrength", "displayName": "Normal Strength", "description": "Scales the impact of the clear coat normal map", "type": "Float", @@ -2309,28 +2309,28 @@ "max": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_clearCoatNormalStrength" + "name": "m_layer3_m_clearCoatNormalStrength" } }, { - "id": "normalMap", + "name": "normalMap", "displayName": "Normal Map", "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_clearCoatNormalMap" + "name": "m_layer3_m_clearCoatNormalMap" } }, { - "id": "useNormalMap", + "name": "useNormalMap", "displayName": " Use Texture", "description": "Whether to use the normal map", "type": "Bool", "defaultValue": true }, { - "id": "normalMapUv", + "name": "normalMapUv", "displayName": " UV", "description": "Normal map UV set", "type": "Enum", @@ -2338,30 +2338,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_clearCoatNormalMapUvIndex" + "name": "m_layer3_m_clearCoatNormalMapUvIndex" } } ], "layer3_occlusion": [ { - "id": "diffuseTextureMap", + "name": "diffuseTextureMap", "displayName": "Diffuse AO", "description": "Texture for defining occlusion area for diffuse ambient lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_diffuseOcclusionMap" + "name": "m_layer3_m_diffuseOcclusionMap" } }, { - "id": "diffuseUseTexture", + "name": "diffuseUseTexture", "displayName": " Use Texture", "description": "Whether to use the Diffuse AO map.", "type": "Bool", "defaultValue": true }, { - "id": "diffuseTextureMapUv", + "name": "diffuseTextureMapUv", "displayName": " UV", "description": "Diffuse AO map UV set.", "type": "Enum", @@ -2369,11 +2369,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_diffuseOcclusionMapUvIndex" + "name": "m_layer3_m_diffuseOcclusionMapUvIndex" } }, { - "id": "diffuseFactor", + "name": "diffuseFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Diffuse AO", "type": "Float", @@ -2382,28 +2382,28 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_diffuseOcclusionFactor" + "name": "m_layer3_m_diffuseOcclusionFactor" } }, { - "id": "specularTextureMap", + "name": "specularTextureMap", "displayName": "Specular Cavity", "description": "Texture for defining occlusion area for specular lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_specularOcclusionMap" + "name": "m_layer3_m_specularOcclusionMap" } }, { - "id": "specularUseTexture", + "name": "specularUseTexture", "displayName": " Use Texture", "description": "Whether to use the Specular Cavity map.", "type": "Bool", "defaultValue": true }, { - "id": "specularTextureMapUv", + "name": "specularTextureMapUv", "displayName": " UV", "description": "Specular Cavity map UV set.", "type": "Enum", @@ -2411,11 +2411,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_specularOcclusionMapUvIndex" + "name": "m_layer3_m_specularOcclusionMapUvIndex" } }, { - "id": "specularFactor", + "name": "specularFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Specular Cavity", "type": "Float", @@ -2424,20 +2424,20 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_specularOcclusionFactor" + "name": "m_layer3_m_specularOcclusionFactor" } } ], "layer3_emissive": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable the emissive group", "type": "Bool", "defaultValue": false }, { - "id": "unit", + "name": "unit", "displayName": "Units", "description": "The photometric units of the Intensity property.", "type": "Enum", @@ -2445,18 +2445,18 @@ "defaultValue": "Ev100" }, { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_layer3_m_emissiveColor" + "name": "m_layer3_m_emissiveColor" } }, { - "id": "intensity", + "name": "intensity", "displayName": "Intensity", "description": "The amount of energy emitted.", "type": "Float", @@ -2467,24 +2467,24 @@ "softMax": 16 }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining emissive area.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_emissiveMap" + "name": "m_layer3_m_emissiveMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Emissive map UV set", "type": "Enum", @@ -2492,30 +2492,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_emissiveMapUvIndex" + "name": "m_layer3_m_emissiveMapUvIndex" } } ], "layer3_parallax": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Height Map", "description": "Displacement height map, which can be used for layer blending and/or a parallax effect.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_layer3_m_heightmap" + "name": "m_layer3_m_heightmap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the height map.", "type": "Bool", "defaultValue": true }, { - "id": "factor", + "name": "factor", "displayName": "Scale", "description": "The total height of the height map in local model units.", "type": "Float", @@ -2524,11 +2524,11 @@ "softMax": 0.1, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_heightmapScale" + "name": "m_layer3_m_heightmapScale" } }, { - "id": "offset", + "name": "offset", "displayName": "Offset", "description": "Adjusts the overall displacement amount in local model units.", "type": "Float", @@ -2537,13 +2537,13 @@ "softMax": 0.1, "connection": { "type": "ShaderInput", - "id": "m_layer3_m_heightmapOffset" + "name": "m_layer3_m_heightmapOffset" } } ], "layer3_uv": [ { - "id": "center", + "name": "center", "displayName": "Center", "description": "Center point for scaling and rotation transformations.", "type": "vector2", @@ -2551,7 +2551,7 @@ "defaultValue": [ 0.5, 0.5 ] }, { - "id": "tileU", + "name": "tileU", "displayName": "Tile U", "description": "Scales texture coordinates in V.", "type": "float", @@ -2559,7 +2559,7 @@ "step": 0.1 }, { - "id": "tileV", + "name": "tileV", "displayName": "Tile V", "description": "Scales texture coordinates in V.", "type": "float", @@ -2567,7 +2567,7 @@ "step": 0.1 }, { - "id": "offsetU", + "name": "offsetU", "displayName": "Offset U", "description": "Offsets texture coordinates in the U direction.", "type": "float", @@ -2577,7 +2577,7 @@ "step": 0.001 }, { - "id": "offsetV", + "name": "offsetV", "displayName": "Offset V", "description": "Offsets texture coordinates in the V direction.", "type": "float", @@ -2587,7 +2587,7 @@ "step": 0.001 }, { - "id": "rotateDegrees", + "name": "rotateDegrees", "displayName": "Rotate", "description": "Rotates the texture coordinates (degrees).", "type": "float", @@ -2597,7 +2597,7 @@ "step": 1.0 }, { - "id": "scale", + "name": "scale", "displayName": "Scale", "description": "Scales texture coordinates in both U and V.", "type": "float", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype index 8b7e4b1c7e..6eb82b85ae 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype @@ -4,68 +4,68 @@ "version": 3, "groups": [ { - "id": "baseColor", + "name": "baseColor", "displayName": "Base Color", "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." }, { - "id": "metallic", + "name": "metallic", "displayName": "Metallic", "description": "Properties for configuring whether the surface is metallic or not." }, { - "id": "roughness", + "name": "roughness", "displayName": "Roughness", "description": "Properties for configuring how rough the surface appears." }, { - "id": "specularF0", + "name": "specularF0", "displayName": "Specular Reflectance f0", "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." }, { - "id": "normal", + "name": "normal", "displayName": "Normal", "description": "Properties related to configuring surface normal." }, { - "id": "occlusion", + "name": "occlusion", "displayName": "Occlusion", "description": "Properties for baked textures that represent geometric occlusion of light." }, { - "id": "emissive", + "name": "emissive", "displayName": "Emissive", "description": "Properties to add light emission, independent of other lights in the scene." }, { - "id": "clearCoat", + "name": "clearCoat", "displayName": "Clear Coat", "description": "Properties for configuring gloss clear coat" }, { - "id": "parallax", + "name": "parallax", "displayName": "Displacement", "description": "Properties for parallax effect produced by a height map." }, { - "id": "opacity", + "name": "opacity", "displayName": "Opacity", "description": "Properties for configuring the materials transparency." }, { - "id": "uv", + "name": "uv", "displayName": "UVs", "description": "Properties for configuring UV transforms." }, { // Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader - "id": "irradiance", + "name": "irradiance", "displayName": "Irradiance", "description": "Properties for configuring the irradiance used in global illumination." }, { - "id": "general", + "name": "general", "displayName": "General Settings", "description": "General settings." } @@ -73,97 +73,97 @@ "properties": { "general": [ { - "id": "applySpecularAA", + "name": "applySpecularAA", "displayName": "Apply Specular AA", "description": "Whether to apply specular anti-aliasing in the shader.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_applySpecularAA" + "name": "o_applySpecularAA" } }, { - "id": "enableShadows", + "name": "enableShadows", "displayName": "Enable Shadows", "description": "Whether to use the shadow maps.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableShadows" + "name": "o_enableShadows" } }, { - "id": "enableDirectionalLights", + "name": "enableDirectionalLights", "displayName": "Enable Directional Lights", "description": "Whether to use directional lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableDirectionalLights" + "name": "o_enableDirectionalLights" } }, { - "id": "enablePunctualLights", + "name": "enablePunctualLights", "displayName": "Enable Punctual Lights", "description": "Whether to use punctual lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enablePunctualLights" + "name": "o_enablePunctualLights" } }, { - "id": "enableAreaLights", + "name": "enableAreaLights", "displayName": "Enable Area Lights", "description": "Whether to use area lights.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableAreaLights" + "name": "o_enableAreaLights" } }, { - "id": "enableIBL", + "name": "enableIBL", "displayName": "Enable IBL", "description": "Whether to use Image Based Lighting (IBL).", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableIBL" + "name": "o_enableIBL" } }, { - "id": "forwardPassIBLSpecular", + "name": "forwardPassIBLSpecular", "displayName": "Forward Pass IBL Specular", "description": "Whether to apply IBL specular in the forward pass.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_materialUseForwardPassIBLSpecular" + "name": "o_materialUseForwardPassIBLSpecular" } } ], "baseColor": [ { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_baseColor" + "name": "m_baseColor" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", "type": "Float", @@ -172,28 +172,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_baseColorFactor" + "name": "m_baseColorFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Base color texture map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_baseColorMap" + "name": "m_baseColorMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Base color map UV set", "type": "Enum", @@ -201,11 +201,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_baseColorMapUvIndex" + "name": "m_baseColorMapUvIndex" } }, { - "id": "textureBlendMode", + "name": "textureBlendMode", "displayName": "Texture Blend Mode", "description": "Selects the equation to use when combining Color, Factor, and Texture.", "type": "Enum", @@ -213,13 +213,13 @@ "defaultValue": "Multiply", "connection": { "type": "ShaderOption", - "id": "o_baseColorTextureBlendMode" + "name": "o_baseColorTextureBlendMode" } } ], "metallic": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "This value is linear, black is non-metal and white means raw metal.", "type": "Float", @@ -228,28 +228,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_metallicFactor" + "name": "m_metallicFactor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_metallicMap" + "name": "m_metallicMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Metallic map UV set", "type": "Enum", @@ -257,30 +257,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_metallicMapUvIndex" + "name": "m_metallicMapUvIndex" } } ], "roughness": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface roughness.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_roughnessMap" + "name": "m_roughnessMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Roughness map UV set", "type": "Enum", @@ -288,12 +288,12 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_roughnessMapUvIndex" + "name": "m_roughnessMapUvIndex" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "lowerBound", + "name": "lowerBound", "displayName": "Lower Bound", "description": "The roughness value that corresponds to black in the texture.", "type": "Float", @@ -302,12 +302,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughnessLowerBound" + "name": "m_roughnessLowerBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "upperBound", + "name": "upperBound", "displayName": "Upper Bound", "description": "The roughness value that corresponds to white in the texture.", "type": "Float", @@ -316,12 +316,12 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughnessUpperBound" + "name": "m_roughnessUpperBound" } }, { // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Controls the roughness value", "type": "Float", @@ -330,13 +330,13 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughnessFactor" + "name": "m_roughnessFactor" } } ], "specularF0": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", "type": "Float", @@ -345,28 +345,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_specularF0Factor" + "name": "m_specularF0Factor" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface reflectance.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_specularF0Map" + "name": "m_specularF0Map" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Specular reflection map UV set", "type": "Enum", @@ -374,31 +374,31 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_specularF0MapUvIndex" + "name": "m_specularF0MapUvIndex" } }, // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR { - "id": "enableMultiScatterCompensation", + "name": "enableMultiScatterCompensation", "displayName": "Multiscattering Compensation", "description": "Whether to enable multiple scattering compensation.", "type": "Bool", "connection": { "type": "ShaderOption", - "id": "o_specularF0_enableMultiScatterCompensation" + "name": "o_specularF0_enableMultiScatterCompensation" } } ], "clearCoat": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable clear coat", "type": "Bool", "defaultValue": false }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the percentage of effect applied", "type": "Float", @@ -407,28 +407,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_clearCoatFactor" + "name": "m_clearCoatFactor" } }, { - "id": "influenceMap", + "name": "influenceMap", "displayName": " Influence Map", "description": "Strength factor texture", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_clearCoatInfluenceMap" + "name": "m_clearCoatInfluenceMap" } }, { - "id": "useInfluenceMap", + "name": "useInfluenceMap", "displayName": " Use Texture", "description": "Whether to use the texture, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "influenceMapUv", + "name": "influenceMapUv", "displayName": " UV", "description": "Strength factor map UV set", "type": "Enum", @@ -436,11 +436,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_clearCoatInfluenceMapUvIndex" + "name": "m_clearCoatInfluenceMapUvIndex" } }, { - "id": "roughness", + "name": "roughness", "displayName": "Roughness", "description": "Clear coat layer roughness", "type": "Float", @@ -449,28 +449,28 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_clearCoatRoughness" + "name": "m_clearCoatRoughness" } }, { - "id": "roughnessMap", + "name": "roughnessMap", "displayName": " Roughness Map", "description": "Texture for defining surface roughness", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_clearCoatRoughnessMap" + "name": "m_clearCoatRoughnessMap" } }, { - "id": "useRoughnessMap", + "name": "useRoughnessMap", "displayName": " Use Texture", "description": "Whether to use the texture, or just default to the roughness value.", "type": "Bool", "defaultValue": true }, { - "id": "roughnessMapUv", + "name": "roughnessMapUv", "displayName": " UV", "description": "Roughness map UV set", "type": "Enum", @@ -478,11 +478,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_clearCoatRoughnessMapUvIndex" + "name": "m_clearCoatRoughnessMapUvIndex" } }, { - "id": "normalStrength", + "name": "normalStrength", "displayName": "Normal Strength", "description": "Scales the impact of the clear coat normal map", "type": "Float", @@ -491,28 +491,28 @@ "max": 2.0, "connection": { "type": "ShaderInput", - "id": "m_clearCoatNormalStrength" + "name": "m_clearCoatNormalStrength" } }, { - "id": "normalMap", + "name": "normalMap", "displayName": "Normal Map", "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_clearCoatNormalMap" + "name": "m_clearCoatNormalMap" } }, { - "id": "useNormalMap", + "name": "useNormalMap", "displayName": " Use Texture", "description": "Whether to use the normal map", "type": "Bool", "defaultValue": true }, { - "id": "normalMapUv", + "name": "normalMapUv", "displayName": " UV", "description": "Normal map UV set", "type": "Enum", @@ -520,30 +520,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_clearCoatNormalMapUvIndex" + "name": "m_clearCoatNormalMapUvIndex" } } ], "normal": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface normal direction.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_normalMap" + "name": "m_normalMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture, or just rely on vertex normals.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Normal map UV set", "type": "Enum", @@ -551,33 +551,33 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_normalMapUvIndex" + "name": "m_normalMapUvIndex" } }, { - "id": "flipX", + "name": "flipX", "displayName": "Flip X Channel", "description": "Flip tangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_flipNormalX" + "name": "m_flipNormalX" } }, { - "id": "flipY", + "name": "flipY", "displayName": "Flip Y Channel", "description": "Flip bitangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_flipNormalY" + "name": "m_flipNormalY" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the values", "type": "Float", @@ -586,13 +586,13 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_normalFactor" + "name": "m_normalFactor" } } ], "opacity": [ { - "id": "mode", + "name": "mode", "displayName": "Opacity Mode", "description": "Indicates the general approach how transparency is to be applied.", "type": "Enum", @@ -600,11 +600,11 @@ "defaultValue": "Opaque", "connection": { "type": "ShaderOption", - "id": "o_opacity_mode" + "name": "o_opacity_mode" } }, { - "id": "alphaSource", + "name": "alphaSource", "displayName": "Alpha Source", "description": "Indicates whether to get the opacity texture from the Base Color map (Packed) or from a separate greyscale texture (Split).", "type": "Enum", @@ -612,21 +612,21 @@ "defaultValue": "Packed", "connection": { "type": "ShaderOption", - "id": "o_opacity_source" + "name": "o_opacity_source" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining surface opacity.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_opacityMap" + "name": "m_opacityMap" } }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Opacity map UV set", "type": "Enum", @@ -634,11 +634,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_opacityMapUvIndex" + "name": "m_opacityMapUvIndex" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Factor for cutout threshold and blending", "type": "Float", @@ -647,17 +647,17 @@ "defaultValue": 0.5, "connection": { "type": "ShaderInput", - "id": "m_opacityFactor" + "name": "m_opacityFactor" } }, { - "id": "doubleSided", + "name": "doubleSided", "displayName": "Double-sided", "description": "Whether to render back-faces or just front-faces.", "type": "Bool" }, { - "id": "alphaAffectsSpecular", + "name": "alphaAffectsSpecular", "displayName": "Alpha affects specular", "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", "type": "float", @@ -666,13 +666,13 @@ "defaultValue": 0.0, "connection": { "type": "ShaderInput", - "id": "m_opacityAffectsSpecularFactor" + "name": "m_opacityAffectsSpecularFactor" } } ], "uv": [ { - "id": "center", + "name": "center", "displayName": "Center", "description": "Center point for scaling and rotation transformations.", "type": "vector2", @@ -680,7 +680,7 @@ "defaultValue": [ 0.5, 0.5 ] }, { - "id": "tileU", + "name": "tileU", "displayName": "Tile U", "description": "Scales texture coordinates in U.", "type": "float", @@ -688,7 +688,7 @@ "step": 0.1 }, { - "id": "tileV", + "name": "tileV", "displayName": "Tile V", "description": "Scales texture coordinates in V.", "type": "float", @@ -696,7 +696,7 @@ "step": 0.1 }, { - "id": "offsetU", + "name": "offsetU", "displayName": "Offset U", "description": "Offsets texture coordinates in the U direction.", "type": "float", @@ -705,7 +705,7 @@ "max": 1.0 }, { - "id": "offsetV", + "name": "offsetV", "displayName": "Offset V", "description": "Offsets texture coordinates in the V direction.", "type": "float", @@ -714,7 +714,7 @@ "max": 1.0 }, { - "id": "rotateDegrees", + "name": "rotateDegrees", "displayName": "Rotate", "description": "Rotates the texture coordinates (degrees).", "type": "float", @@ -724,7 +724,7 @@ "step": 1.0 }, { - "id": "scale", + "name": "scale", "displayName": "Scale", "description": "Scales texture coordinates in both U and V.", "type": "float", @@ -734,24 +734,24 @@ ], "occlusion": [ { - "id": "diffuseTextureMap", + "name": "diffuseTextureMap", "displayName": "Diffuse AO", "description": "Texture for defining occlusion area for diffuse ambient lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_diffuseOcclusionMap" + "name": "m_diffuseOcclusionMap" } }, { - "id": "diffuseUseTexture", + "name": "diffuseUseTexture", "displayName": " Use Texture", "description": "Whether to use the Diffuse AO map.", "type": "Bool", "defaultValue": true }, { - "id": "diffuseTextureMapUv", + "name": "diffuseTextureMapUv", "displayName": " UV", "description": "Diffuse AO map UV set.", "type": "Enum", @@ -759,11 +759,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_diffuseOcclusionMapUvIndex" + "name": "m_diffuseOcclusionMapUvIndex" } }, { - "id": "diffuseFactor", + "name": "diffuseFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Diffuse AO", "type": "Float", @@ -772,28 +772,28 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_diffuseOcclusionFactor" + "name": "m_diffuseOcclusionFactor" } }, { - "id": "specularTextureMap", + "name": "specularTextureMap", "displayName": "Specular Cavity", "description": "Texture for defining occlusion area for specular lighting.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_specularOcclusionMap" + "name": "m_specularOcclusionMap" } }, { - "id": "specularUseTexture", + "name": "specularUseTexture", "displayName": " Use Texture", "description": "Whether to use the Specular Cavity map.", "type": "Bool", "defaultValue": true }, { - "id": "specularTextureMapUv", + "name": "specularTextureMapUv", "displayName": " UV", "description": "Specular Cavity map UV set.", "type": "Enum", @@ -801,11 +801,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_specularOcclusionMapUvIndex" + "name": "m_specularOcclusionMapUvIndex" } }, { - "id": "specularFactor", + "name": "specularFactor", "displayName": " Factor", "description": "Strength factor for scaling the values of Specular Cavity", "type": "Float", @@ -814,20 +814,20 @@ "softMax": 2.0, "connection": { "type": "ShaderInput", - "id": "m_specularOcclusionFactor" + "name": "m_specularOcclusionFactor" } } ], "emissive": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable the emissive group", "type": "Bool", "defaultValue": false }, { - "id": "unit", + "name": "unit", "displayName": "Units", "description": "The photometric units of the Intensity property.", "type": "Enum", @@ -835,18 +835,18 @@ "defaultValue": "Ev100" }, { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_emissiveColor" + "name": "m_emissiveColor" } }, { - "id": "intensity", + "name": "intensity", "displayName": "Intensity", "description": "The amount of energy emitted.", "type": "Float", @@ -857,24 +857,24 @@ "softMax": 16 }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture", "description": "Texture for defining emissive area.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_emissiveMap" + "name": "m_emissiveMap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Emissive map UV set", "type": "Enum", @@ -882,30 +882,30 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_emissiveMapUvIndex" + "name": "m_emissiveMapUvIndex" } } ], "parallax": [ { - "id": "textureMap", + "name": "textureMap", "displayName": "Height Map", "description": "Displacement height map to create parallax effect.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_heightmap" + "name": "m_heightmap" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the height map.", "type": "Bool", "defaultValue": true }, { - "id": "textureMapUv", + "name": "textureMapUv", "displayName": "UV", "description": "Height map UV set", "type": "Enum", @@ -913,11 +913,11 @@ "defaultValue": "Tiled", "connection": { "type": "ShaderInput", - "id": "m_parallaxUvIndex" + "name": "m_parallaxUvIndex" } }, { - "id": "factor", + "name": "factor", "displayName": "Height Map Scale", "description": "The total height of the height map in local model units.", "type": "Float", @@ -926,11 +926,11 @@ "softMax": 0.1, "connection": { "type": "ShaderInput", - "id": "m_heightmapScale" + "name": "m_heightmapScale" } }, { - "id": "offset", + "name": "offset", "displayName": "Offset", "description": "Adjusts the overall displacement amount in local model units.", "type": "Float", @@ -939,11 +939,11 @@ "softMax": 0.1, "connection": { "type": "ShaderInput", - "id": "m_heightmapOffset" + "name": "m_heightmapOffset" } }, { - "id": "algorithm", + "name": "algorithm", "displayName": "Algorithm", "description": "Select the algorithm to use for parallax mapping.", "type": "Enum", @@ -951,11 +951,11 @@ "defaultValue": "POM", "connection": { "type": "ShaderOption", - "id": "o_parallax_algorithm" + "name": "o_parallax_algorithm" } }, { - "id": "quality", + "name": "quality", "displayName": "Quality", "description": "Quality of parallax mapping.", "type": "Enum", @@ -963,43 +963,43 @@ "defaultValue": "Low", "connection": { "type": "ShaderOption", - "id": "o_parallax_quality" + "name": "o_parallax_quality" } }, { - "id": "pdo", + "name": "pdo", "displayName": "Pixel Depth Offset", "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_parallax_enablePixelDepthOffset" + "name": "o_parallax_enablePixelDepthOffset" } }, { - "id": "showClipping", + "name": "showClipping", "displayName": "Show Clipping", "description": "Highlight areas where the height map is clipped by the mesh surface.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_parallax_highlightClipping" + "name": "o_parallax_highlightClipping" } } ], "irradiance": [ // Note: this property group is used in the DiffuseGlobalIllumination pass and not by the main forward shader { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ] }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", "type": "Float", diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 7019289466..04b6222404 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -40,12 +40,12 @@ namespace AZ AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::PropertyConnection, "{C2F37C26-D7EF-4142-A650-EF50BB18610F}"); PropertyConnection() = default; - PropertyConnection(MaterialPropertyOutputType type, AZStd::string_view nameId, int32_t shaderIndex = -1); + PropertyConnection(MaterialPropertyOutputType type, AZStd::string_view fieldName, int32_t shaderIndex = -1); MaterialPropertyOutputType m_type = MaterialPropertyOutputType::Invalid; //! The name of a specific shader setting. This will either be a ShaderResourceGroup input or a ShaderOption, depending on m_type - AZStd::string m_nameId; + AZStd::string m_fieldName; //! For m_type==ShaderOption, this is either the index of a specific shader in m_shaderCollection, or -1 which means every shader in m_shaderCollection. //! For m_type==ShaderInput, this field is not used. @@ -58,8 +58,8 @@ namespace AZ { AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::GroupDefinition, "{B2D0FC5C-72A3-435E-A194-1BFDABAC253D}"); - //! The unique name of the property group. A property's full ID will be groupNameId.propertyNameId. - AZStd::string m_nameId; + //! The unique name of the property group. The full property ID will be groupName.propertyName + AZStd::string m_name; // Editor metadata ... AZStd::string m_displayName; @@ -74,7 +74,7 @@ namespace AZ static const float DefaultMax; static const float DefaultStep; - AZStd::string m_nameId; //!< The name of the property within the property group. The full ID will be groupNameId.propertyNameId. + AZStd::string m_name; //!< The name of the property within the property group. The full property ID will be groupName.propertyName. MaterialPropertyVisibility m_visibility = MaterialPropertyVisibility::Default; @@ -130,7 +130,7 @@ namespace AZ AZStd::vector m_groups; //! Collection of all available user-facing properties - AZStd::map m_properties; + AZStd::map m_properties; }; AZStd::string m_description; @@ -151,9 +151,9 @@ namespace AZ //! Copy over UV custom names to the properties enum values. void ResolveUvEnums(); - const GroupDefinition* FindGroup(AZStd::string_view groupNameId) const; + const GroupDefinition* FindGroup(AZStd::string_view groupName) const; - const PropertyDefinition* FindProperty(AZStd::string_view groupNameId, AZStd::string_view propertyNameId) const; + const PropertyDefinition* FindProperty(AZStd::string_view groupName, AZStd::string_view propertyName) const; //! Construct a complete list of group definitions, including implicit groups, arranged in the same order as the source data //! Groups with the same name will be consolidated into a single entry diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h index 3976ef989b..d8a0cf0e7d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h @@ -70,8 +70,8 @@ namespace AZ virtual ~Material(); - //! Finds the material property index from the material property name - MaterialPropertyIndex FindPropertyIndex(const Name& name) const; + //! Finds the material property index from the material property ID + MaterialPropertyIndex FindPropertyIndex(const Name& propertyId) const; //! Sets the value of a material property. The template data type must match the property's data type. //! @return true if property value was changed diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h index 45c8f0dc30..bc020b8129 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h @@ -35,7 +35,7 @@ namespace AZ AZ_DISABLE_COPY_MOVE(MaterialPropertiesLayout); size_t GetPropertyCount() const; - MaterialPropertyIndex FindPropertyIndex(const Name& propertyName) const; + MaterialPropertyIndex FindPropertyIndex(const Name& propertyId) const; const MaterialPropertyDescriptor* GetPropertyDescriptor(MaterialPropertyIndex index) const; private: diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp index f3d499ac78..578e69e5ca 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp @@ -27,7 +27,8 @@ namespace AZ { namespace Field { - static constexpr const char id[] = "id"; + static constexpr const char id[] = "id"; // legacy field, replaced by "name" + static constexpr const char name[] = "name"; static constexpr const char displayName[] = "displayName"; static constexpr const char description[] = "description"; static constexpr const char type[] = "type"; @@ -47,6 +48,7 @@ namespace AZ static const AZStd::string_view AcceptedFields[] = { Field::id, + Field::name, Field::displayName, Field::description, Field::type, @@ -218,7 +220,10 @@ namespace AZ } } - result.Combine(ContinueLoadingFromJsonObjectField(&property->m_nameId, azrtti_typeid(), inputValue, Field::id, context)); + // Field::id is the legacy field, replaced by Field::name. If both are present, Field::name will take priority. + result.Combine(ContinueLoadingFromJsonObjectField(&property->m_name, azrtti_typeid(), inputValue, Field::id, context)); + result.Combine(ContinueLoadingFromJsonObjectField(&property->m_name, azrtti_typeid(), inputValue, Field::name, context)); + result.Combine(ContinueLoadingFromJsonObjectField(&property->m_displayName, azrtti_typeid(), inputValue, Field::displayName, context)); result.Combine(ContinueLoadingFromJsonObjectField(&property->m_description, azrtti_typeid(), inputValue, Field::description, context)); result.Combine(ContinueLoadingFromJsonObjectField(&property->m_dataType, azrtti_typeid(), inputValue, Field::type, context)); @@ -374,7 +379,7 @@ namespace AZ outputValue.SetObject(); const AZStd::string emptyString; - result.Combine(ContinueStoringToJsonObjectField(outputValue, Field::id, &property->m_nameId, &emptyString, azrtti_typeid(), context)); + result.Combine(ContinueStoringToJsonObjectField(outputValue, Field::name, &property->m_name, &emptyString, azrtti_typeid(), context)); result.Combine(ContinueStoringToJsonObjectField(outputValue, Field::displayName, &property->m_displayName, &emptyString, azrtti_typeid(), context)); result.Combine(ContinueStoringToJsonObjectField(outputValue, Field::description, &property->m_description, &emptyString, azrtti_typeid(), context)); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyValueSerializer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyValueSerializer.cpp index 060a563c53..3b2d36451a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyValueSerializer.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyValueSerializer.cpp @@ -62,18 +62,18 @@ namespace AZ return context.Report(JsonSerializationResult::Tasks::ReadField, JsonSerializationResult::Outcomes::Catastrophic, "Material type reference not found."); } - // Construct the full property name (groupId.propertyId) by parsing it from the JSON path string. - size_t startPropertyNameId = context.GetPath().Get().rfind('/'); - size_t startGroupNameId = context.GetPath().Get().rfind('/', startPropertyNameId-1); - AZStd::string_view groupNameId = context.GetPath().Get().substr(startGroupNameId + 1, startPropertyNameId - startGroupNameId - 1); - AZStd::string_view propertyNameId = context.GetPath().Get().substr(startPropertyNameId + 1); + // Construct the full property name (groupName.propertyName) by parsing it from the JSON path string. + size_t startPropertyName = context.GetPath().Get().rfind('/'); + size_t startGroupName = context.GetPath().Get().rfind('/', startPropertyName-1); + AZStd::string_view groupName = context.GetPath().Get().substr(startGroupName + 1, startPropertyName - startGroupName - 1); + AZStd::string_view propertyName = context.GetPath().Get().substr(startPropertyName + 1); JSR::ResultCode result(JSR::Tasks::ReadField); - auto propertyDefinition = materialType->FindProperty(groupNameId, propertyNameId); + auto propertyDefinition = materialType->FindProperty(groupName, propertyName); if (!propertyDefinition) { - AZStd::string message = AZStd::string::format("Property '%.*s.%.*s' not found in material type.", AZ_STRING_ARG(groupNameId), AZ_STRING_ARG(propertyNameId)); + AZStd::string message = AZStd::string::format("Property '%.*s.%.*s' not found in material type.", AZ_STRING_ARG(groupName), AZ_STRING_ARG(propertyName)); return context.Report(JsonSerializationResult::Tasks::ReadField, JsonSerializationResult::Outcomes::Unsupported, message); } else 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 5a95cb35a6..1a6c7868a3 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -52,7 +52,8 @@ namespace AZ serializeContext->Class() ->Version(1) ->Field("type", &PropertyConnection::m_type) - ->Field("id", &PropertyConnection::m_nameId) + ->Field("id", &PropertyConnection::m_fieldName) // The old reflection, replaced by "name" + ->Field("name", &PropertyConnection::m_fieldName) ->Field("shaderIndex", &PropertyConnection::m_shaderIndex) ; @@ -60,7 +61,8 @@ namespace AZ serializeContext->Class() ->Version(1) - ->Field("id", &GroupDefinition::m_nameId) + ->Field("id", &GroupDefinition::m_name) // The old reflection, replaced by "name" + ->Field("name", &GroupDefinition::m_name) ->Field("displayName", &GroupDefinition::m_displayName) ->Field("description", &GroupDefinition::m_description) ; @@ -96,9 +98,9 @@ namespace AZ } } - MaterialTypeSourceData::PropertyConnection::PropertyConnection(MaterialPropertyOutputType type, AZStd::string_view nameId, int32_t shaderIndex) + MaterialTypeSourceData::PropertyConnection::PropertyConnection(MaterialPropertyOutputType type, AZStd::string_view fieldName, int32_t shaderIndex) : m_type(type) - , m_nameId(nameId) + , m_fieldName(fieldName) , m_shaderIndex(shaderIndex) { } @@ -107,11 +109,11 @@ namespace AZ const float MaterialTypeSourceData::PropertyDefinition::DefaultMax = std::numeric_limits::max(); const float MaterialTypeSourceData::PropertyDefinition::DefaultStep = 0.1f; - const MaterialTypeSourceData::GroupDefinition* MaterialTypeSourceData::FindGroup(AZStd::string_view groupNameId) const + const MaterialTypeSourceData::GroupDefinition* MaterialTypeSourceData::FindGroup(AZStd::string_view groupName) const { for (const GroupDefinition& group : m_propertyLayout.m_groups) { - if (group.m_nameId == groupNameId) + if (group.m_name == groupName) { return &group; } @@ -120,9 +122,9 @@ namespace AZ return nullptr; } - const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::string_view groupNameId, AZStd::string_view propertyNameId) const + const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::string_view groupName, AZStd::string_view propertyName) const { - auto groupIter = m_propertyLayout.m_properties.find(groupNameId); + auto groupIter = m_propertyLayout.m_properties.find(groupName); if (groupIter == m_propertyLayout.m_properties.end()) { return nullptr; @@ -130,7 +132,7 @@ namespace AZ for (const PropertyDefinition& property : groupIter->second) { - if (property.m_nameId == propertyNameId) + if (property.m_name == propertyName) { return &property; } @@ -169,24 +171,24 @@ namespace AZ AZStd::unordered_set foundGroups; for (const auto& groupDefinition : m_propertyLayout.m_groups) { - if (foundGroups.insert(groupDefinition.m_nameId).second) + if (foundGroups.insert(groupDefinition.m_name).second) { groupDefinitions.push_back(groupDefinition); } else { - AZ_Warning("Material source data", false, "Duplicate group '%s' found.", groupDefinition.m_nameId.c_str()); + AZ_Warning("Material source data", false, "Duplicate group '%s' found.", groupDefinition.m_name.c_str()); } } // Some groups are defined implicitly, in the "properties" section where a group name is used but not explicitly defined in the "groups" section. for (const auto& propertyListPair : m_propertyLayout.m_properties) { - const AZStd::string& groupNameId = propertyListPair.first; - if (foundGroups.insert(groupNameId).second) + const AZStd::string& groupName = propertyListPair.first; + if (foundGroups.insert(groupName).second) { MaterialTypeSourceData::GroupDefinition groupDefinition; - groupDefinition.m_nameId = groupNameId; + groupDefinition.m_name = groupName; groupDefinitions.push_back(groupDefinition); } } @@ -203,12 +205,12 @@ namespace AZ for (const auto& propertyListPair : m_propertyLayout.m_properties) { - const AZStd::string& groupNameId = propertyListPair.first; + const AZStd::string& groupName = propertyListPair.first; const auto& propertyList = propertyListPair.second; for (const auto& propertyDefinition : propertyList) { - const AZStd::string& propertyNameId = propertyDefinition.m_nameId; - if (!callback(groupNameId, propertyNameId, propertyDefinition)) + const AZStd::string& propertyName = propertyDefinition.m_name; + if (!callback(groupName, propertyName, propertyDefinition)) { return; } @@ -225,15 +227,15 @@ namespace AZ for (const auto& groupDefinition : GetGroupDefinitionsInDisplayOrder()) { - const AZStd::string& groupNameId = groupDefinition.m_nameId; - const auto propertyListItr = m_propertyLayout.m_properties.find(groupNameId); + const AZStd::string& groupName = groupDefinition.m_name; + const auto propertyListItr = m_propertyLayout.m_properties.find(groupName); if (propertyListItr != m_propertyLayout.m_properties.end()) { const auto& propertyList = propertyListItr->second; for (const auto& propertyDefinition : propertyList) { - const AZStd::string& propertyNameId = propertyDefinition.m_nameId; - if (!callback(groupNameId, propertyNameId, propertyDefinition)) + const AZStd::string& propertyName = propertyDefinition.m_name; + if (!callback(groupName, propertyName, propertyDefinition)) { return; } @@ -249,7 +251,7 @@ namespace AZ const uint32_t index = propertyValue.GetValue(); if (index >= propertyDefinition.m_enumValues.size()) { - AZ_Error("Material source data", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_nameId.c_str()); + AZ_Error("Material source data", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str()); return false; } @@ -272,7 +274,7 @@ namespace AZ imageAsset.GetId(), imageAsset.GetType(), platformName, imageAssetInfo, rootFilePath); if (!result) { - AZ_Error("Material source data", false, "Image asset could not be found for property: '%s'.", propertyDefinition.m_nameId.c_str()); + AZ_Error("Material source data", false, "Image asset could not be found for property: '%s'.", propertyDefinition.m_name.c_str()); return false; } } @@ -340,13 +342,13 @@ namespace AZ for (auto& groupIter : m_propertyLayout.m_properties) { - const AZStd::string& groupNameId = groupIter.first; + const AZStd::string& groupName = groupIter.first; for (const PropertyDefinition& property : groupIter.second) { // Register the property... - MaterialPropertyId propertyId{ groupNameId, property.m_nameId }; + MaterialPropertyId propertyId{ groupName, property.m_name }; if (!propertyId.IsValid()) { @@ -366,16 +368,16 @@ namespace AZ switch (output.m_type) { case MaterialPropertyOutputType::ShaderInput: - materialTypeAssetCreator.ConnectMaterialPropertyToShaderInput(Name{ output.m_nameId.data() }); + materialTypeAssetCreator.ConnectMaterialPropertyToShaderInput(Name{ output.m_fieldName.data() }); break; case MaterialPropertyOutputType::ShaderOption: if (output.m_shaderIndex >= 0) { - materialTypeAssetCreator.ConnectMaterialPropertyToShaderOption(Name{ output.m_nameId.data() }, output.m_shaderIndex); + materialTypeAssetCreator.ConnectMaterialPropertyToShaderOption(Name{ output.m_fieldName.data() }, output.m_shaderIndex); } else { - materialTypeAssetCreator.ConnectMaterialPropertyToShaderOptions(Name{ output.m_nameId.data() }); + materialTypeAssetCreator.ConnectMaterialPropertyToShaderOptions(Name{ output.m_fieldName.data() }); } break; case MaterialPropertyOutputType::Invalid: diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp index d44ed40c7b..c87646e17d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp @@ -386,9 +386,9 @@ namespace AZ return m_currentChangeId; } - MaterialPropertyIndex Material::FindPropertyIndex(const Name& name) const + MaterialPropertyIndex Material::FindPropertyIndex(const Name& propertyId) const { - return m_layout->FindPropertyIndex(name); + return m_layout->FindPropertyIndex(propertyId); } template diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertiesLayout.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertiesLayout.cpp index 273ea321a6..1c5142031d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertiesLayout.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertiesLayout.cpp @@ -34,9 +34,9 @@ namespace AZ return m_materialPropertyDescriptors.size(); } - MaterialPropertyIndex MaterialPropertiesLayout::FindPropertyIndex(const Name& propertyName) const + MaterialPropertyIndex MaterialPropertiesLayout::FindPropertyIndex(const Name& propertyId) const { - return m_materialPropertyIndexes.Find(propertyName); + return m_materialPropertyIndexes.Find(propertyId); } const MaterialPropertyDescriptor* MaterialPropertiesLayout::GetPropertyDescriptor(MaterialPropertyIndex index) const diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp index 553c3243e1..13effd4eaf 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp @@ -89,14 +89,14 @@ namespace UnitTest } }; - void AddPropertyGroup(MaterialSourceData& material, AZStd::string_view groupNameId) + void AddPropertyGroup(MaterialSourceData& material, AZStd::string_view groupName) { - material.m_properties.insert(groupNameId); + material.m_properties.insert(groupName); } - void AddProperty(MaterialSourceData& material, AZStd::string_view groupNameId, AZStd::string_view propertyNameId, const MaterialPropertyValue& anyValue) + void AddProperty(MaterialSourceData& material, AZStd::string_view groupName, AZStd::string_view propertyName, const MaterialPropertyValue& anyValue) { - material.m_properties[groupNameId][propertyNameId].m_value = anyValue; + material.m_properties[groupName][propertyName].m_value = anyValue; } TEST_F(MaterialSourceDataTests, CreateMaterialAsset_BasicProperties) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocument.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocument.h index 565c9f00a3..bf18d36c2c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocument.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocument.h @@ -32,10 +32,10 @@ namespace AtomToolsFramework // AtomToolsDocumentRequestBus::Handler implementation AZStd::string_view GetAbsolutePath() const override; AZStd::string_view GetRelativePath() const override; - const AZStd::any& GetPropertyValue(const AZ::Name& propertyFullName) const override; - const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const override; + const AZStd::any& GetPropertyValue(const AZ::Name& propertyId) const override; + const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyId) const override; bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const override; - void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) override; + void SetPropertyValue(const AZ::Name& propertyId, const AZStd::any& value) override; bool Open(AZStd::string_view loadPath) override; bool Reopen() override; bool Save() override; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h index 9ee53680ae..68e5e38cbd 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h @@ -42,8 +42,8 @@ namespace AtomToolsFramework AZ_CLASS_ALLOCATOR(DynamicPropertyConfig, AZ::SystemAllocator, 0); DynamicPropertyType m_dataType = DynamicPropertyType::Invalid; - AZ::Name m_id; - AZStd::string m_nameId; + AZ::Name m_id; //!< The full property ID, which will normally be "groupName.propertyName" + AZStd::string m_name; AZStd::string m_displayName; AZStd::string m_groupName; AZStd::string m_description; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h index 900dc3535c..6e5ac6e463 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h @@ -41,27 +41,27 @@ namespace AtomToolsFramework //! Add a group consisting of a collapsable header and widget virtual void AddGroup( - const AZStd::string& groupNameId, + const AZStd::string& groupName, const AZStd::string& groupDisplayName, const AZStd::string& groupDescription, QWidget* groupWidget) = 0; //! Sets the visibility of a specific property group. This impacts both the header and the widget. - virtual void SetGroupVisible(const AZStd::string& groupNameId, bool visible) = 0; + virtual void SetGroupVisible(const AZStd::string& groupName, bool visible) = 0; //! Returns whether a specific property is visible. //! Note this follows the same rules as QWidget::isVisible(), meaning a group could be not visible due to the widget's parents being not visible. - virtual bool IsGroupVisible(const AZStd::string& groupNameId) const = 0; + virtual bool IsGroupVisible(const AZStd::string& groupName) const = 0; //! Returns whether a specific property is explicitly hidden. //! Note this follows the same rules as QWidget::isHidden(), meaning a group that is hidden will not become visible automatically when the parent becomes visible. - virtual bool IsGroupHidden(const AZStd::string& groupNameId) const = 0; + virtual bool IsGroupHidden(const AZStd::string& groupName) const = 0; //! Calls Refresh for a specific InspectorGroupWidget, allowing for non-destructive UI changes - virtual void RefreshGroup(const AZStd::string& groupNameId) = 0; + virtual void RefreshGroup(const AZStd::string& groupName) = 0; //! Calls Rebuild for a specific InspectorGroupWidget, allowing for destructive UI changes - virtual void RebuildGroup(const AZStd::string& groupNameId) = 0; + virtual void RebuildGroup(const AZStd::string& groupName) = 0; //! Calls Refresh for all InspectorGroupWidget, allowing for non-destructive UI changes virtual void RefreshAll() = 0; @@ -70,13 +70,13 @@ namespace AtomToolsFramework virtual void RebuildAll() = 0; //! Expands a specific group - virtual void ExpandGroup(const AZStd::string& groupNameId) = 0; + virtual void ExpandGroup(const AZStd::string& groupName) = 0; //! Collapses a specific group - virtual void CollapseGroup(const AZStd::string& groupNameId) = 0; + virtual void CollapseGroup(const AZStd::string& groupName) = 0; //! Checks the expansion state of a specific group - virtual bool IsGroupExpanded(const AZStd::string& groupNameId) const = 0; + virtual bool IsGroupExpanded(const AZStd::string& groupName) const = 0; //! Expands all groups and headers virtual void ExpandAll() = 0; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h index adcd94ca10..7e655d978e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h @@ -52,33 +52,33 @@ namespace AtomToolsFramework void AddGroupsEnd() override; void AddGroup( - const AZStd::string& groupNameId, + const AZStd::string& groupName, const AZStd::string& groupDisplayName, const AZStd::string& groupDescription, QWidget* groupWidget) override; - void SetGroupVisible(const AZStd::string& groupNameId, bool visible) override; - bool IsGroupVisible(const AZStd::string& groupNameId) const override; - bool IsGroupHidden(const AZStd::string& groupNameId) const override; + void SetGroupVisible(const AZStd::string& groupName, bool visible) override; + bool IsGroupVisible(const AZStd::string& groupName) const override; + bool IsGroupHidden(const AZStd::string& groupName) const override; - void RefreshGroup(const AZStd::string& groupNameId) override; - void RebuildGroup(const AZStd::string& groupNameId) override; + void RefreshGroup(const AZStd::string& groupName) override; + void RebuildGroup(const AZStd::string& groupName) override; void RefreshAll() override; void RebuildAll() override; - void ExpandGroup(const AZStd::string& groupNameId) override; - void CollapseGroup(const AZStd::string& groupNameId) override; - bool IsGroupExpanded(const AZStd::string& groupNameId) const override; + void ExpandGroup(const AZStd::string& groupName) override; + void CollapseGroup(const AZStd::string& groupName) override; + bool IsGroupExpanded(const AZStd::string& groupName) const override; void ExpandAll() override; void CollapseAll() override; protected: - virtual bool ShouldGroupAutoExpanded(const AZStd::string& groupNameId) const; - virtual void OnGroupExpanded(const AZStd::string& groupNameId); - virtual void OnGroupCollapsed(const AZStd::string& groupNameId); - virtual void OnHeaderClicked(const AZStd::string& groupNameId, QMouseEvent* event); + virtual bool ShouldGroupAutoExpanded(const AZStd::string& groupName) const; + virtual void OnGroupExpanded(const AZStd::string& groupName); + virtual void OnGroupCollapsed(const AZStd::string& groupName); + virtual void OnHeaderClicked(const AZStd::string& groupName, QMouseEvent* event); private: QScopedPointer m_ui; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocument.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocument.cpp index 336737f419..1e2c685c3c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocument.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocument.cpp @@ -38,16 +38,16 @@ namespace AtomToolsFramework return m_relativePath; } - const AZStd::any& AtomToolsDocument::GetPropertyValue([[maybe_unused]] const AZ::Name& propertyFullName) const + const AZStd::any& AtomToolsDocument::GetPropertyValue([[maybe_unused]] const AZ::Name& propertyId) const { - AZ_UNUSED(propertyFullName); + AZ_UNUSED(propertyId); AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); return m_invalidValue; } - const AtomToolsFramework::DynamicProperty& AtomToolsDocument::GetProperty([[maybe_unused]] const AZ::Name& propertyFullName) const + const AtomToolsFramework::DynamicProperty& AtomToolsDocument::GetProperty([[maybe_unused]] const AZ::Name& propertyId) const { - AZ_UNUSED(propertyFullName); + AZ_UNUSED(propertyId); AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); return m_invalidProperty; } @@ -59,9 +59,9 @@ namespace AtomToolsFramework return false; } - void AtomToolsDocument::SetPropertyValue([[maybe_unused]] const AZ::Name& propertyFullName, [[maybe_unused]] const AZStd::any& value) + void AtomToolsDocument::SetPropertyValue([[maybe_unused]] const AZ::Name& propertyId, [[maybe_unused]] const AZStd::any& value) { - AZ_UNUSED(propertyFullName); + AZ_UNUSED(propertyId); AZ_UNUSED(value); AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicProperty.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicProperty.cpp index d08728aad1..2054858726 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicProperty.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicProperty.cpp @@ -192,7 +192,7 @@ namespace AtomToolsFramework AZStd::string DynamicProperty::GetDisplayName() const { - return !m_config.m_displayName.empty() ? m_config.m_displayName : m_config.m_nameId; + return !m_config.m_displayName.empty() ? m_config.m_displayName : m_config.m_name; } AZStd::string DynamicProperty::GetGroupName() const diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp index 5eda93ca59..3ec82bbd88 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp @@ -66,7 +66,7 @@ namespace AtomToolsFramework } void InspectorWidget::AddGroup( - const AZStd::string& groupNameId, + const AZStd::string& groupName, const AZStd::string& groupDisplayName, const AZStd::string& groupDescription, QWidget* groupWidget) @@ -76,31 +76,31 @@ namespace AtomToolsFramework groupHeader->setToolTip(groupDescription.c_str()); m_ui->m_groupContentsLayout->addWidget(groupHeader); - groupWidget->setObjectName(groupNameId.c_str()); + groupWidget->setObjectName(groupName.c_str()); groupWidget->setParent(m_ui->m_groupContents); m_ui->m_groupContentsLayout->addWidget(groupWidget); - m_groups[groupNameId] = {groupHeader, groupWidget}; + m_groups[groupName] = {groupHeader, groupWidget}; - connect(groupHeader, &InspectorGroupHeaderWidget::clicked, this, [this, groupNameId](QMouseEvent* event) { - OnHeaderClicked(groupNameId, event); + connect(groupHeader, &InspectorGroupHeaderWidget::clicked, this, [this, groupName](QMouseEvent* event) { + OnHeaderClicked(groupName, event); }); - connect(groupHeader, &InspectorGroupHeaderWidget::expanded, this, [this, groupNameId]() { OnGroupExpanded(groupNameId); }); - connect(groupHeader, &InspectorGroupHeaderWidget::collapsed, this, [this, groupNameId]() { OnGroupCollapsed(groupNameId); }); + connect(groupHeader, &InspectorGroupHeaderWidget::expanded, this, [this, groupName]() { OnGroupExpanded(groupName); }); + connect(groupHeader, &InspectorGroupHeaderWidget::collapsed, this, [this, groupName]() { OnGroupCollapsed(groupName); }); - if (ShouldGroupAutoExpanded(groupNameId)) + if (ShouldGroupAutoExpanded(groupName)) { - ExpandGroup(groupNameId); + ExpandGroup(groupName); } else { - CollapseGroup(groupNameId); + CollapseGroup(groupName); } } - void InspectorWidget::SetGroupVisible(const AZStd::string& groupNameId, bool visible) + void InspectorWidget::SetGroupVisible(const AZStd::string& groupName, bool visible) { - auto groupItr = m_groups.find(groupNameId); + auto groupItr = m_groups.find(groupName); if (groupItr != m_groups.end()) { groupItr->second.m_header->setVisible(visible); @@ -108,29 +108,29 @@ namespace AtomToolsFramework } } - bool InspectorWidget::IsGroupVisible(const AZStd::string& groupNameId) const + bool InspectorWidget::IsGroupVisible(const AZStd::string& groupName) const { - auto groupItr = m_groups.find(groupNameId); + auto groupItr = m_groups.find(groupName); return groupItr != m_groups.end() ? groupItr->second.m_header->isVisible() : false; } - bool InspectorWidget::IsGroupHidden(const AZStd::string& groupNameId) const + bool InspectorWidget::IsGroupHidden(const AZStd::string& groupName) const { - auto groupItr = m_groups.find(groupNameId); + auto groupItr = m_groups.find(groupName); return groupItr != m_groups.end() ? groupItr->second.m_header->isHidden() : false; } - void InspectorWidget::RefreshGroup(const AZStd::string& groupNameId) + void InspectorWidget::RefreshGroup(const AZStd::string& groupName) { - for (auto groupWidget : m_ui->m_groupContents->findChildren(groupNameId.c_str())) + for (auto groupWidget : m_ui->m_groupContents->findChildren(groupName.c_str())) { groupWidget->Refresh(); } } - void InspectorWidget::RebuildGroup(const AZStd::string& groupNameId) + void InspectorWidget::RebuildGroup(const AZStd::string& groupName) { - for (auto groupWidget : m_ui->m_groupContents->findChildren(groupNameId.c_str())) + for (auto groupWidget : m_ui->m_groupContents->findChildren(groupName.c_str())) { groupWidget->Rebuild(); } @@ -152,9 +152,9 @@ namespace AtomToolsFramework } } - void InspectorWidget::ExpandGroup(const AZStd::string& groupNameId) + void InspectorWidget::ExpandGroup(const AZStd::string& groupName) { - auto groupItr = m_groups.find(groupNameId); + auto groupItr = m_groups.find(groupName); if (groupItr != m_groups.end()) { groupItr->second.m_header->SetExpanded(true); @@ -162,9 +162,9 @@ namespace AtomToolsFramework } } - void InspectorWidget::CollapseGroup(const AZStd::string& groupNameId) + void InspectorWidget::CollapseGroup(const AZStd::string& groupName) { - auto groupItr = m_groups.find(groupNameId); + auto groupItr = m_groups.find(groupName); if (groupItr != m_groups.end()) { groupItr->second.m_header->SetExpanded(false); @@ -172,9 +172,9 @@ namespace AtomToolsFramework } } - bool InspectorWidget::IsGroupExpanded(const AZStd::string& groupNameId) const + bool InspectorWidget::IsGroupExpanded(const AZStd::string& groupName) const { - auto groupItr = m_groups.find(groupNameId); + auto groupItr = m_groups.find(groupName); return groupItr != m_groups.end() ? groupItr->second.m_header->IsExpanded() : false; } @@ -196,33 +196,33 @@ namespace AtomToolsFramework } } - bool InspectorWidget::ShouldGroupAutoExpanded(const AZStd::string& groupNameId) const + bool InspectorWidget::ShouldGroupAutoExpanded(const AZStd::string& groupName) const { - AZ_UNUSED(groupNameId); + AZ_UNUSED(groupName); return true; } - void InspectorWidget::OnGroupExpanded(const AZStd::string& groupNameId) + void InspectorWidget::OnGroupExpanded(const AZStd::string& groupName) { - AZ_UNUSED(groupNameId); + AZ_UNUSED(groupName); } - void InspectorWidget::OnGroupCollapsed(const AZStd::string& groupNameId) + void InspectorWidget::OnGroupCollapsed(const AZStd::string& groupName) { - AZ_UNUSED(groupNameId); + AZ_UNUSED(groupName); } - void InspectorWidget::OnHeaderClicked(const AZStd::string& groupNameId, QMouseEvent* event) + void InspectorWidget::OnHeaderClicked(const AZStd::string& groupName, QMouseEvent* event) { if (event->button() == Qt::MouseButton::LeftButton) { - if (!IsGroupExpanded(groupNameId)) + if (!IsGroupExpanded(groupName)) { - ExpandGroup(groupNameId); + ExpandGroup(groupName); } else { - CollapseGroup(groupNameId); + CollapseGroup(groupName); } return; } @@ -230,8 +230,8 @@ namespace AtomToolsFramework if (event->button() == Qt::MouseButton::RightButton) { QMenu menu; - menu.addAction("Expand", [this, groupNameId]() { ExpandGroup(groupNameId); })->setEnabled(!IsGroupExpanded(groupNameId)); - menu.addAction("Collapse", [this, groupNameId]() { CollapseGroup(groupNameId); })->setEnabled(IsGroupExpanded(groupNameId)); + menu.addAction("Expand", [this, groupName]() { ExpandGroup(groupName); })->setEnabled(!IsGroupExpanded(groupName)); + menu.addAction("Collapse", [this, groupName]() { CollapseGroup(groupName); })->setEnabled(IsGroupExpanded(groupName)); menu.addAction("Expand All", [this]() { ExpandAll(); }); menu.addAction("Collapse All", [this]() { CollapseAll(); }); menu.exec(event->globalPos()); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index 641cf63d04..0b14f9313f 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -74,7 +74,7 @@ namespace AtomToolsFramework void ConvertToPropertyConfig(AtomToolsFramework::DynamicPropertyConfig& propertyConfig, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition) { propertyConfig.m_dataType = ConvertToEditableType(propertyDefinition.m_dataType); - propertyConfig.m_nameId = propertyDefinition.m_nameId; + propertyConfig.m_name = propertyDefinition.m_name; propertyConfig.m_displayName = propertyDefinition.m_displayName; propertyConfig.m_description = propertyDefinition.m_description; propertyConfig.m_defaultValue = ConvertToEditableType(propertyDefinition.m_value); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index d032f35e38..17e292ac16 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -59,7 +59,7 @@ namespace MaterialEditor return &m_materialTypeSourceData; } - const AZStd::any& MaterialDocument::GetPropertyValue(const AZ::Name& propertyFullName) const + const AZStd::any& MaterialDocument::GetPropertyValue(const AZ::Name& propertyId) const { using namespace AZ; using namespace RPI; @@ -70,10 +70,10 @@ namespace MaterialEditor return m_invalidValue; } - const auto it = m_properties.find(propertyFullName); + const auto it = m_properties.find(propertyId); if (it == m_properties.end()) { - AZ_Error("MaterialDocument", false, "Material document property could not be found: '%s'.", propertyFullName.GetCStr()); + AZ_Error("MaterialDocument", false, "Material document property could not be found: '%s'.", propertyId.GetCStr()); return m_invalidValue; } @@ -81,7 +81,7 @@ namespace MaterialEditor return property.GetValue(); } - const AtomToolsFramework::DynamicProperty& MaterialDocument::GetProperty(const AZ::Name& propertyFullName) const + const AtomToolsFramework::DynamicProperty& MaterialDocument::GetProperty(const AZ::Name& propertyId) const { if (!IsOpen()) { @@ -89,10 +89,10 @@ namespace MaterialEditor return m_invalidProperty; } - const auto it = m_properties.find(propertyFullName); + const auto it = m_properties.find(propertyId); if (it == m_properties.end()) { - AZ_Error("MaterialDocument", false, "Material document property could not be found: '%s'.", propertyFullName.GetCStr()); + AZ_Error("MaterialDocument", false, "Material document property could not be found: '%s'.", propertyId.GetCStr()); return m_invalidProperty; } @@ -118,7 +118,7 @@ namespace MaterialEditor return it->second; } - void MaterialDocument::SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) + void MaterialDocument::SetPropertyValue(const AZ::Name& propertyId, const AZStd::any& value) { using namespace AZ; using namespace RPI; @@ -129,10 +129,10 @@ namespace MaterialEditor return; } - const auto it = m_properties.find(propertyFullName); + const auto it = m_properties.find(propertyId); if (it == m_properties.end()) { - AZ_Error("MaterialDocument", false, "Material document property could not be found: '%s'.", propertyFullName.GetCStr()); + AZ_Error("MaterialDocument", false, "Material document property could not be found: '%s'.", propertyId.GetCStr()); return; } @@ -143,8 +143,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicProperty& property = it->second; property.SetValue(AtomToolsFramework::ConvertToEditableType(propertyValue)); - const AZ::RPI::MaterialPropertyId propertyId = AZ::RPI::MaterialPropertyId::Parse(propertyFullName.GetStringView()); - const auto propertyIndex = m_materialInstance->FindPropertyIndex(propertyFullName); + const auto propertyIndex = m_materialInstance->FindPropertyIndex(propertyId); if (!propertyIndex.IsNull()) { if (m_materialInstance->SetPropertyValue(propertyIndex, propertyValue)) @@ -593,8 +592,9 @@ namespace MaterialEditor bool result = true; // populate sourceData with properties that meet the filter - m_materialTypeSourceData.EnumerateProperties([this, &sourceData, &propertyFilter, &result](const AZStd::string& groupNameId, const AZStd::string& propertyNameId, const auto& propertyDefinition) { - const MaterialPropertyId propertyId(groupNameId, propertyNameId); + m_materialTypeSourceData.EnumerateProperties([this, &sourceData, &propertyFilter, &result](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { + + const MaterialPropertyId propertyId(groupName, propertyName); const auto it = m_properties.find(propertyId.GetFullName()); if (it != m_properties.end() && propertyFilter(it->second)) @@ -609,7 +609,7 @@ namespace MaterialEditor return false; } - sourceData.m_properties[groupNameId][propertyNameId].m_value = propertyValue; + sourceData.m_properties[groupName][propertyName].m_value = propertyValue; } } return true; @@ -770,11 +770,11 @@ namespace MaterialEditor // Populate the property map from a combination of source data and assets // Assets must still be used for now because they contain the final accumulated value after all other materials // in the hierarchy are applied - m_materialTypeSourceData.EnumerateProperties([this, &parentPropertyValues](const AZStd::string& groupNameId, const AZStd::string& propertyNameId, const auto& propertyDefinition) { + m_materialTypeSourceData.EnumerateProperties([this, &parentPropertyValues](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { AtomToolsFramework::DynamicPropertyConfig propertyConfig; // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = MaterialPropertyId(groupNameId, propertyNameId).GetCStr(); + propertyConfig.m_id = MaterialPropertyId(groupName, propertyName).GetCStr(); const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); const bool propertyIndexInBounds = propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size(); @@ -786,8 +786,8 @@ namespace MaterialEditor propertyConfig.m_showThumbnail = true; propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]); propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(parentPropertyValues[propertyIndex.GetIndex()]); - auto groupDefinition = m_materialTypeSourceData.FindGroup(groupNameId); - propertyConfig.m_groupName = groupDefinition ? groupDefinition->m_displayName : groupNameId; + auto groupDefinition = m_materialTypeSourceData.FindGroup(groupName); + propertyConfig.m_groupName = groupDefinition ? groupDefinition->m_displayName : groupName; m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); } return true; @@ -796,7 +796,7 @@ namespace MaterialEditor // Populate the property group visibility map for (MaterialTypeSourceData::GroupDefinition& group : m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder()) { - m_propertyGroupVisibility[AZ::Name{group.m_nameId}] = true; + m_propertyGroupVisibility[AZ::Name{group.m_name}] = true; } // Adding properties for material type and parent as part of making dynamic @@ -808,7 +808,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicPropertyConfig propertyConfig; propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Asset; propertyConfig.m_id = "overview.materialType"; - propertyConfig.m_nameId = "materialType"; + propertyConfig.m_name = "materialType"; propertyConfig.m_displayName = "Material Type"; propertyConfig.m_groupName = "Overview"; propertyConfig.m_description = "The material type defines the layout, properties, default values, shader connections, and other " @@ -823,7 +823,7 @@ namespace MaterialEditor propertyConfig = {}; propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Asset; propertyConfig.m_id = "overview.parentMaterial"; - propertyConfig.m_nameId = "parentMaterial"; + propertyConfig.m_name = "parentMaterial"; propertyConfig.m_displayName = "Parent Material"; propertyConfig.m_groupName = "Overview"; propertyConfig.m_description = @@ -846,7 +846,7 @@ namespace MaterialEditor propertyConfig = {}; propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::String; propertyConfig.m_id = MaterialPropertyId(UvGroupName, shaderInput).GetCStr(); - propertyConfig.m_nameId = shaderInput; + propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = shaderInput; propertyConfig.m_groupName = "UV Sets"; propertyConfig.m_description = shaderInput; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h index d732680b7b..03997a2a91 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h @@ -43,10 +43,10 @@ namespace MaterialEditor //////////////////////////////////////////////////////////////////////// // AtomToolsFramework::AtomToolsDocument //////////////////////////////////////////////////////////////////////// - const AZStd::any& GetPropertyValue(const AZ::Name& propertyFullName) const override; - const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const override; + const AZStd::any& GetPropertyValue(const AZ::Name& propertyId) const override; + const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyId) const override; bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const override; - void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) override; + void SetPropertyValue(const AZ::Name& propertyId, const AZStd::any& value) override; bool Open(AZStd::string_view loadPath) override; bool Reopen() override; bool Save() override; 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 28d7d3d3f5..df0b179dc1 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp @@ -44,20 +44,20 @@ namespace MaterialEditor AtomToolsFramework::InspectorWidget::Reset(); } - bool MaterialInspector::ShouldGroupAutoExpanded(const AZStd::string& groupNameId) const + bool MaterialInspector::ShouldGroupAutoExpanded(const AZStd::string& groupName) const { - auto stateItr = m_windowSettings->m_inspectorCollapsedGroups.find(GetGroupSaveStateKey(groupNameId)); + auto stateItr = m_windowSettings->m_inspectorCollapsedGroups.find(GetGroupSaveStateKey(groupName)); return stateItr == m_windowSettings->m_inspectorCollapsedGroups.end(); } - void MaterialInspector::OnGroupExpanded(const AZStd::string& groupNameId) + void MaterialInspector::OnGroupExpanded(const AZStd::string& groupName) { - m_windowSettings->m_inspectorCollapsedGroups.erase(GetGroupSaveStateKey(groupNameId)); + m_windowSettings->m_inspectorCollapsedGroups.erase(GetGroupSaveStateKey(groupName)); } - void MaterialInspector::OnGroupCollapsed(const AZStd::string& groupNameId) + void MaterialInspector::OnGroupCollapsed(const AZStd::string& groupName) { - m_windowSettings->m_inspectorCollapsedGroups.insert(GetGroupSaveStateKey(groupNameId)); + m_windowSettings->m_inspectorCollapsedGroups.insert(GetGroupSaveStateKey(groupName)); } void MaterialInspector::OnDocumentOpened(const AZ::Uuid& documentId) @@ -86,9 +86,9 @@ namespace MaterialEditor AddGroupsEnd(); } - AZ::Crc32 MaterialInspector::GetGroupSaveStateKey(const AZStd::string& groupNameId) const + AZ::Crc32 MaterialInspector::GetGroupSaveStateKey(const AZStd::string& groupName) const { - return AZ::Crc32(AZStd::string::format("MaterialInspector::PropertyGroup::%s::%s", m_documentPath.c_str(), groupNameId.c_str())); + return AZ::Crc32(AZStd::string::format("MaterialInspector::PropertyGroup::%s::%s", m_documentPath.c_str(), groupName.c_str())); } bool MaterialInspector::CompareInstanceNodeProperties( @@ -105,10 +105,10 @@ namespace MaterialEditor MaterialDocumentRequestBus::EventResult( materialTypeSourceData, m_documentId, &MaterialDocumentRequestBus::Events::GetMaterialTypeSourceData); - const AZStd::string groupNameId = "overview"; + const AZStd::string groupName = "overview"; const AZStd::string groupDisplayName = "Overview"; const AZStd::string groupDescription = materialTypeSourceData->m_description; - auto& group = m_groups[groupNameId]; + auto& group = m_groups[groupName]; AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( @@ -122,9 +122,9 @@ namespace MaterialEditor // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( - &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupNameId), + &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), [this](const auto source, const auto target) { return CompareInstanceNodeProperties(source, target); }); - AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget); + AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); } void MaterialInspector::AddUvNamesGroup() @@ -132,10 +132,10 @@ namespace MaterialEditor AZ::Data::Asset materialAsset; MaterialDocumentRequestBus::EventResult(materialAsset, m_documentId, &MaterialDocumentRequestBus::Events::GetAsset); - const AZStd::string groupNameId = UvGroupName; + const AZStd::string groupName = UvGroupName; const AZStd::string groupDisplayName = "UV Sets"; const AZStd::string groupDescription = "UV set names in this material, which can be renamed to match those in the model."; - auto& group = m_groups[groupNameId]; + auto& group = m_groups[groupName]; const auto& uvNameMap = materialAsset->GetMaterialTypeAsset()->GetUvNameMap(); group.m_properties.reserve(uvNameMap.size()); @@ -145,7 +145,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupNameId, uvNamePair.m_shaderInput.ToString()).GetFullName()); + AZ::RPI::MaterialPropertyId(groupName, uvNamePair.m_shaderInput.ToString()).GetFullName()); group.m_properties.push_back(property); property.SetValue(property.GetConfig().m_parentValue); @@ -153,9 +153,9 @@ namespace MaterialEditor // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( - &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupNameId), + &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), [this](const auto source, const auto target) { return CompareInstanceNodeProperties(source, target); }); - AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget); + AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); } void MaterialInspector::AddPropertiesGroup() @@ -166,14 +166,14 @@ namespace MaterialEditor for (const auto& groupDefinition : materialTypeSourceData->GetGroupDefinitionsInDisplayOrder()) { - const AZStd::string& groupNameId = groupDefinition.m_nameId; - const AZStd::string& groupDisplayName = !groupDefinition.m_displayName.empty() ? groupDefinition.m_displayName : groupNameId; + const AZStd::string& groupName = groupDefinition.m_name; + const AZStd::string& groupDisplayName = !groupDefinition.m_displayName.empty() ? groupDefinition.m_displayName : groupName; const AZStd::string& groupDescription = !groupDefinition.m_description.empty() ? groupDefinition.m_description : groupDisplayName; - auto& group = m_groups[groupNameId]; + auto& group = m_groups[groupName]; const auto& propertyLayout = materialTypeSourceData->m_propertyLayout; - const auto& propertyListItr = propertyLayout.m_properties.find(groupNameId); + const auto& propertyListItr = propertyLayout.m_properties.find(groupName); if (propertyListItr != propertyLayout.m_properties.end()) { group.m_properties.reserve(propertyListItr->second.size()); @@ -182,21 +182,21 @@ namespace MaterialEditor AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupNameId, propertyDefinition.m_nameId).GetFullName()); + AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name).GetFullName()); group.m_properties.push_back(property); } } // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( - &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupNameId), + &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), [this](const auto source, const auto target) { return CompareInstanceNodeProperties(source, target); }); - AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget); + AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); bool isGroupVisible = false; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( - isGroupVisible, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsPropertyGroupVisible, AZ::Name{groupNameId}); - SetGroupVisible(groupNameId, isGroupVisible); + isGroupVisible, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsPropertyGroupVisible, AZ::Name{groupName}); + SetGroupVisible(groupName, isGroupVisible); } } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h index 845a8cb0f7..dedcd79f5e 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h @@ -37,12 +37,12 @@ namespace MaterialEditor void Reset() override; protected: - bool ShouldGroupAutoExpanded(const AZStd::string& groupNameId) const override; - void OnGroupExpanded(const AZStd::string& groupNameId) override; - void OnGroupCollapsed(const AZStd::string& groupNameId) override; + bool ShouldGroupAutoExpanded(const AZStd::string& groupName) const override; + void OnGroupExpanded(const AZStd::string& groupName) override; + void OnGroupCollapsed(const AZStd::string& groupName) override; private: - AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupNameId) const; + AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupName) const; bool CompareInstanceNodeProperties( const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) const; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/SettingsDialog/SettingsWidget.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/SettingsDialog/SettingsWidget.cpp index c7d4b195a3..2a061a2ed6 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/SettingsDialog/SettingsWidget.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/SettingsDialog/SettingsWidget.cpp @@ -35,26 +35,26 @@ namespace MaterialEditor void SettingsWidget::AddDocumentSettingsGroup() { - const AZStd::string groupNameId = "documentSettings"; + const AZStd::string groupName = "documentSettings"; const AZStd::string groupDisplayName = "Document Settings"; const AZStd::string groupDescription = "Document Settings"; const AZ::Crc32 saveStateKey(AZStd::string::format("SettingsWidget::DocumentSettingsGroup")); AddGroup( - groupNameId, groupDisplayName, groupDescription, + groupName, groupDisplayName, groupDescription, new AtomToolsFramework::InspectorPropertyGroupWidget( m_documentSettings.get(), nullptr, m_documentSettings->TYPEINFO_Uuid(), this, this, saveStateKey)); } void SettingsWidget::AddDocumentSystemSettingsGroup() { - const AZStd::string groupNameId = "documentSystemSettings"; + const AZStd::string groupName = "documentSystemSettings"; const AZStd::string groupDisplayName = "Document System Settings"; const AZStd::string groupDescription = "Document System Settings"; const AZ::Crc32 saveStateKey(AZStd::string::format("SettingsWidget::DocumentSystemSettingsGroup")); AddGroup( - groupNameId, groupDisplayName, groupDescription, + groupName, groupDisplayName, groupDescription, new AtomToolsFramework::InspectorPropertyGroupWidget( m_documentSystemSettings.get(), nullptr, m_documentSystemSettings->TYPEINFO_Uuid(), this, this, saveStateKey)); } 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 d4269c2438..19768802b0 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp @@ -53,19 +53,19 @@ namespace MaterialEditor void ViewportSettingsInspector::AddGeneralGroup() { - const AZStd::string groupNameId = "generalSettings"; + const AZStd::string groupName = "generalSettings"; const AZStd::string groupDisplayName = "General Settings"; const AZStd::string groupDescription = "General Settings"; AddGroup( - groupNameId, groupDisplayName, groupDescription, + groupName, groupDisplayName, groupDescription, new AtomToolsFramework::InspectorPropertyGroupWidget( - m_viewportSettings.get(), nullptr, m_viewportSettings->TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupNameId))); + m_viewportSettings.get(), nullptr, m_viewportSettings->TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName))); } void ViewportSettingsInspector::AddModelGroup() { - const AZStd::string groupNameId = "modelSettings"; + const AZStd::string groupName = "modelSettings"; const AZStd::string groupDisplayName = "Model Settings"; const AZStd::string groupDescription = "Model Settings"; @@ -93,12 +93,12 @@ namespace MaterialEditor if (m_modelPreset) { auto inspectorWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( - m_modelPreset.get(), nullptr, m_modelPreset.get()->TYPEINFO_Uuid(), this, groupWidget, GetGroupSaveStateKey(groupNameId)); + m_modelPreset.get(), nullptr, m_modelPreset.get()->TYPEINFO_Uuid(), this, groupWidget, GetGroupSaveStateKey(groupName)); groupWidget->layout()->addWidget(inspectorWidget); } - AddGroup(groupNameId, groupDisplayName, groupDescription, groupWidget); + AddGroup(groupName, groupDisplayName, groupDescription, groupWidget); } void ViewportSettingsInspector::AddModelPreset() @@ -152,7 +152,7 @@ namespace MaterialEditor void ViewportSettingsInspector::AddLightingGroup() { - const AZStd::string groupNameId = "lightingSettings"; + const AZStd::string groupName = "lightingSettings"; const AZStd::string groupDisplayName = "Lighting Settings"; const AZStd::string groupDescription = "Lighting Settings"; @@ -181,12 +181,12 @@ namespace MaterialEditor { auto inspectorWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( m_lightingPreset.get(), nullptr, m_lightingPreset.get()->TYPEINFO_Uuid(), this, groupWidget, - GetGroupSaveStateKey(groupNameId)); + GetGroupSaveStateKey(groupName)); groupWidget->layout()->addWidget(inspectorWidget); } - AddGroup(groupNameId, groupDisplayName, groupDescription, groupWidget); + AddGroup(groupName, groupDisplayName, groupDescription, groupWidget); } void ViewportSettingsInspector::AddLightingPreset() @@ -354,25 +354,25 @@ namespace MaterialEditor return savePath; } - AZ::Crc32 ViewportSettingsInspector::GetGroupSaveStateKey(const AZStd::string& groupNameId) const + AZ::Crc32 ViewportSettingsInspector::GetGroupSaveStateKey(const AZStd::string& groupName) const { - return AZ::Crc32(AZStd::string::format("ViewportSettingsInspector::PropertyGroup::%s", groupNameId.c_str())); + return AZ::Crc32(AZStd::string::format("ViewportSettingsInspector::PropertyGroup::%s", groupName.c_str())); } - bool ViewportSettingsInspector::ShouldGroupAutoExpanded(const AZStd::string& groupNameId) const + bool ViewportSettingsInspector::ShouldGroupAutoExpanded(const AZStd::string& groupName) const { - auto stateItr = m_windowSettings->m_inspectorCollapsedGroups.find(GetGroupSaveStateKey(groupNameId)); + auto stateItr = m_windowSettings->m_inspectorCollapsedGroups.find(GetGroupSaveStateKey(groupName)); return stateItr == m_windowSettings->m_inspectorCollapsedGroups.end(); } - void ViewportSettingsInspector::OnGroupExpanded(const AZStd::string& groupNameId) + void ViewportSettingsInspector::OnGroupExpanded(const AZStd::string& groupName) { - m_windowSettings->m_inspectorCollapsedGroups.erase(GetGroupSaveStateKey(groupNameId)); + m_windowSettings->m_inspectorCollapsedGroups.erase(GetGroupSaveStateKey(groupName)); } - void ViewportSettingsInspector::OnGroupCollapsed(const AZStd::string& groupNameId) + void ViewportSettingsInspector::OnGroupCollapsed(const AZStd::string& groupName) { - m_windowSettings->m_inspectorCollapsedGroups.insert(GetGroupSaveStateKey(groupNameId)); + m_windowSettings->m_inspectorCollapsedGroups.insert(GetGroupSaveStateKey(groupName)); } } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h index d1cd7a7cf3..6299ddb1f2 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h @@ -75,10 +75,10 @@ namespace MaterialEditor AZStd::string GetDefaultUniqueSaveFilePath(const AZStd::string& baseName) const; - AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupNameId) const; - bool ShouldGroupAutoExpanded(const AZStd::string& groupNameId) const override; - void OnGroupExpanded(const AZStd::string& groupNameId) override; - void OnGroupCollapsed(const AZStd::string& groupNameId) override; + AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupName) const; + bool ShouldGroupAutoExpanded(const AZStd::string& groupName) const override; + void OnGroupExpanded(const AZStd::string& groupName) override; + void OnGroupCollapsed(const AZStd::string& groupName) override; AZ::Render::ModelPresetPtr m_modelPreset; AZ::Render::LightingPresetPtr m_lightingPreset; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index a3152faf87..f10a125456 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -169,7 +169,7 @@ namespace AZ void MaterialPropertyInspector::AddDetailsGroup() { - const AZStd::string& groupNameId = "Details"; + const AZStd::string& groupName = "Details"; const AZStd::string& groupDisplayName = "Details"; const AZStd::string& groupDescription = ""; @@ -235,15 +235,15 @@ namespace AZ propertyGroupContainer->layout()->addWidget(materialInfoWidget); - AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupContainer); + AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupContainer); } void MaterialPropertyInspector::AddUvNamesGroup() { - const AZStd::string groupNameId = AZ::RPI::UvGroupName; + const AZStd::string groupName = AZ::RPI::UvGroupName; const AZStd::string groupDisplayName = "UV Sets"; const AZStd::string groupDescription = "UV set names in this material, which can be renamed to match those in the model."; - auto& group = m_groups[groupNameId]; + auto& group = m_groups[groupName]; const RPI::MaterialUvNameMap& uvNameMap = m_editData.m_materialAsset->GetMaterialTypeAsset()->GetUvNameMap(); group.m_properties.reserve(uvNameMap.size()); @@ -257,8 +257,8 @@ namespace AZ propertyConfig = {}; propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::String; - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupNameId, shaderInputStr).GetCStr(); - propertyConfig.m_nameId = shaderInputStr; + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInputStr).GetCStr(); + propertyConfig.m_name = shaderInputStr; propertyConfig.m_displayName = shaderInputStr; propertyConfig.m_groupName = groupDisplayName; propertyConfig.m_description = shaderInputStr; @@ -271,8 +271,8 @@ namespace AZ // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( - &group, nullptr, group.TYPEINFO_Uuid(), this, this, GetSaveStateKeyForGroup(groupNameId)); - AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget); + &group, nullptr, group.TYPEINFO_Uuid(), this, this, GetSaveStateKeyForGroup(groupName)); + AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); } void MaterialPropertyInspector::Populate() @@ -285,13 +285,13 @@ namespace AZ // Copy all of the properties from the material asset to the source data that will be exported for (const auto& groupDefinition : m_editData.m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder()) { - const AZStd::string& groupNameId = groupDefinition.m_nameId; - const AZStd::string& groupDisplayName = !groupDefinition.m_displayName.empty() ? groupDefinition.m_displayName : groupNameId; + const AZStd::string& groupName = groupDefinition.m_name; + const AZStd::string& groupDisplayName = !groupDefinition.m_displayName.empty() ? groupDefinition.m_displayName : groupName; const AZStd::string& groupDescription = !groupDefinition.m_description.empty() ? groupDefinition.m_description : groupDisplayName; - auto& group = m_groups[groupNameId]; + auto& group = m_groups[groupName]; const auto& propertyLayout = m_editData.m_materialTypeSourceData.m_propertyLayout; - const auto& propertyListItr = propertyLayout.m_properties.find(groupNameId); + const auto& propertyListItr = propertyLayout.m_properties.find(groupName); if (propertyListItr != propertyLayout.m_properties.end()) { group.m_properties.reserve(propertyListItr->second.size()); @@ -300,7 +300,7 @@ namespace AZ AtomToolsFramework::DynamicPropertyConfig propertyConfig; // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupNameId, propertyDefinition.m_nameId).GetFullName(); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name).GetFullName(); AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, propertyDefinition); @@ -316,8 +316,8 @@ namespace AZ // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( - &group, nullptr, group.TYPEINFO_Uuid(), this, this, GetSaveStateKeyForGroup(groupNameId)); - AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget); + &group, nullptr, group.TYPEINFO_Uuid(), this, this, GetSaveStateKeyForGroup(groupName)); + AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); } AddGroupsEnd(); @@ -496,11 +496,11 @@ namespace AZ } } - AZ::Crc32 MaterialPropertyInspector::GetSaveStateKeyForGroup(const AZStd::string& groupNameId) const + AZ::Crc32 MaterialPropertyInspector::GetSaveStateKeyForGroup(const AZStd::string& groupName) const { return AZ::Crc32(AZStd::string::format( "MaterialPropertyInspector::PropertyGroup::%s::%s", m_editData.m_materialAssetId.ToString().c_str(), - groupNameId.c_str())); + groupName.c_str())); } bool MaterialPropertyInspector::AreNodePropertyValuesEqual( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h index 11eb2cec51..d3142ddc95 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h @@ -100,7 +100,7 @@ namespace AZ void RunEditorMaterialFunctors(); void UpdateMaterialInstanceProperty(const AtomToolsFramework::DynamicProperty& property); - AZ::Crc32 GetSaveStateKeyForGroup(const AZStd::string& groupNameId) const; + AZ::Crc32 GetSaveStateKeyForGroup(const AZStd::string& groupName) const; static bool AreNodePropertyValuesEqual( const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index e7059ccdf7..070c42fd7c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -137,8 +137,8 @@ namespace AZ // Copy all of the properties from the material asset to the source data that will be exported result = true; - editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupNameId, const AZStd::string& propertyNameId, const auto& propertyDefinition) { - const AZ::RPI::MaterialPropertyId propertyId(groupNameId, propertyNameId); + 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()); @@ -170,7 +170,7 @@ namespace AZ return true; } - exportData.m_properties[groupNameId][propertyDefinition.m_nameId].m_value = propertyValue; + exportData.m_properties[groupName][propertyDefinition.m_name].m_value = propertyValue; return true; }); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp index 91b519a06b..64bc54bae8 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp @@ -81,7 +81,7 @@ namespace AZ { AddGroupsBegin(); - const AZStd::string groupNameId = "ModelUvMap"; + const AZStd::string groupName = "ModelUvMap"; const AZStd::string groupDisplayName = "Material to Model UV Map"; const AZStd::string groupDescription = "Custom map that maps a UV name from the material to one from the model."; @@ -96,8 +96,8 @@ namespace AZ const AZStd::string materialUvName = m_materialUvNames[i].m_uvName.GetStringView(); propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Enum; - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupNameId, shaderInput).GetFullName(); - propertyConfig.m_nameId = shaderInput; + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput).GetFullName(); + propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = materialUvName; propertyConfig.m_description = shaderInput; propertyConfig.m_defaultValue = 0u; @@ -108,7 +108,7 @@ namespace AZ m_group.m_properties.back().SetValue(AZStd::any(m_modelUvNameIndices[i])); } - AddGroup(groupNameId, groupDisplayName, groupDescription, + AddGroup(groupName, groupDisplayName, groupDescription, new AtomToolsFramework::InspectorPropertyGroupWidget(&m_group, nullptr, m_group.TYPEINFO_Uuid(), this)); AddGroupsEnd(); @@ -238,7 +238,7 @@ namespace AZ ResetModelUvNameIndices(); - const AZStd::string groupNameId = "ModelUvMap"; + const AZStd::string groupName = "ModelUvMap"; size_t uvSize = m_materialUvNames.size(); for (size_t i = 0u; i < uvSize; ++i) @@ -248,8 +248,8 @@ namespace AZ const AZStd::string materialUvName = m_materialUvNames[i].m_uvName.GetStringView(); propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Enum; - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupNameId, shaderInput).GetFullName(); - propertyConfig.m_nameId = shaderInput; + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput).GetFullName(); + propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = materialUvName; propertyConfig.m_description = shaderInput; propertyConfig.m_defaultValue = 0u; From 71c7fc021781a0b0e61cf98de225928dc26b8026 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 17 Sep 2021 23:12:24 -0700 Subject: [PATCH 028/115] Updated unit tests to work with the new convention for property name vs property ID. This revealed that the approach of reflecting both the old "id" and the new "name" would not work, because whenn saving it would write out both fields. So I decied to just give up on backward compatibility. This will be much cleaner than trying to continue supporting "id" as a field name, it is uncommon for users to make their own material types at this point, and if they have made some it is very easy to search and replace "id" with "name" update their files. All .materialtype files have been updated. RPI unit tests now pass. ASV still passes. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../ReflectionProbeVisualization.materialtype | 158 +++++++++--------- .../Special/ShadowCatcher.materialtype | 8 +- .../RPI.Builders/Material/MaterialBuilder.cpp | 2 +- .../Material/MaterialPropertySerializer.cpp | 5 - .../Material/MaterialTypeSourceData.cpp | 6 +- .../MaterialPropertySerializerTests.cpp | 140 ++++++++-------- .../Material/MaterialSourceDataTests.cpp | 30 ++-- .../Material/MaterialTypeSourceDataTests.cpp | 54 +++--- .../Materials/Types/AutoBrick.materialtype | 52 +++--- .../Materials/Types/MinimalPBR.materialtype | 14 +- 10 files changed, 231 insertions(+), 238 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/ReflectionProbe/ReflectionProbeVisualization.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/ReflectionProbe/ReflectionProbeVisualization.materialtype index 9a2edc9fca..17209771e5 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/ReflectionProbe/ReflectionProbeVisualization.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/ReflectionProbe/ReflectionProbeVisualization.materialtype @@ -5,7 +5,7 @@ "properties": { "general": [ { - "id": "texcoord", + "name": "texcoord", "displayName": "Texture Coordinate Stream", "description": "Which UV channel to use when sampling textures.", "type": "Int", @@ -14,75 +14,75 @@ "max": 8 }, { - "id": "enableShadows", + "name": "enableShadows", "displayName": "Enable Shadows", "description": "Whether to use the shadow maps.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_enableShadows" + "name": "o_enableShadows" } }, { - "id": "enableDirectionalLights", + "name": "enableDirectionalLights", "displayName": "Enable Directional Lights", "description": "Whether to use directional lights.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_enableDirectionalLights" + "name": "o_enableDirectionalLights" } }, { - "id": "enablePunctualLights", + "name": "enablePunctualLights", "displayName": "Enable Punctual Lights", "description": "Whether to use punctual lights.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_enablePunctualLights" + "name": "o_enablePunctualLights" } }, { - "id": "enableAreaLights", + "name": "enableAreaLights", "displayName": "Enable Area Lights", "description": "Whether to use area lights.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_enableAreaLights" + "name": "o_enableAreaLights" } }, { - "id": "enableIBL", + "name": "enableIBL", "displayName": "Enable IBL", "description": "Whether to use Image Based Lighting (IBL).", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_enableIBL" + "name": "o_enableIBL" } } ], "baseColor": [ { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_baseColor" + "name": "m_baseColor" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", "type": "Float", @@ -91,31 +91,31 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_baseColorFactor" + "name": "m_baseColorFactor" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture map.", "type": "Bool", "defaultValue": true }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture Map", "description": "Base color texture map", "type": "Image", "defaultValue": "Textures/Default/default_basecolor.tif", "connection": { "type": "ShaderInput", - "id": "m_baseColorMap" + "name": "m_baseColorMap" } } ], "metallic": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "This value is linear, black is non-metal and white means raw metal.", "type": "Float", @@ -124,30 +124,30 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_metallicFactor" + "name": "m_metallicFactor" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture map, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture Map", "description": "", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_metallicMap" + "name": "m_metallicMap" } } ], "roughness": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the values", "type": "Float", @@ -156,31 +156,31 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughnessFactor" + "name": "m_roughnessFactor" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture map, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture Map", "description": "Texture map for defining surface roughness.", "type": "Image", "defaultValue": "Textures/Default/default_roughness.tif", "connection": { "type": "ShaderInput", - "id": "m_roughnessMap" + "name": "m_roughnessMap" } } ], "specularF0": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", "type": "Float", @@ -189,51 +189,51 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_specularF0Factor" + "name": "m_specularF0Factor" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture map, or just default to the Factor value.", "type": "Bool", "defaultValue": true }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture Map", "description": "Texture map for defining surface reflectance.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_specularF0Map" + "name": "m_specularF0Map" } }, { - "id": "applySpecularAA", + "name": "applySpecularAA", "displayName": "Apply Specular AA", "description": "Whether to apply specular anti-aliasing in the shader.", "type": "Bool", "defaultValue": true, "connection": { "type": "ShaderOption", - "id": "o_applySpecularAA" + "name": "o_applySpecularAA" } }, { - "id": "enableMultiScatterCompensation", + "name": "enableMultiScatterCompensation", "displayName": "Multiscattering Compensation", "description": "Whether to enable multiple scattering compensation.", "type": "Bool", "connection": { "type": "ShaderOption", - "id": "o_specularF0_enableMultiScatterCompensation" + "name": "o_specularF0_enableMultiScatterCompensation" } } ], "normal": [ { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the values", "type": "Float", @@ -243,85 +243,85 @@ "max": 2.0, "connection": { "type": "ShaderInput", - "id": "m_normalFactor" + "name": "m_normalFactor" } }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture map, or just rely on vertex normals.", "type": "Bool", "defaultValue": true }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture Map", "description": "Texture map for defining surface normal direction.", "type": "Image", "defaultValue": "Textures/Default/default_normal.tif", "connection": { "type": "ShaderInput", - "id": "m_normalMap" + "name": "m_normalMap" } }, { - "id": "flipX", + "name": "flipX", "displayName": "Flip X Channel", "description": "Flip tangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_flipNormalX" + "name": "m_flipNormalX" } }, { - "id": "flipY", + "name": "flipY", "displayName": "Flip Y Channel", "description": "Flip bitangent direction for this normal map.", "type": "Bool", "defaultValue": false, "connection": { "type": "ShaderInput", - "id": "m_flipNormalY" + "name": "m_flipNormalY" } } ], "opacity": [ { - "id": "mode", + "name": "mode", "displayName": "Opacity Mode", "description": "Opacity mode for this texture. 0: Opaque, 1: Cutout, 2:Blended", "type": "Uint", "defaultValue": 0, "connection": { "type": "ShaderOption", - "id": "o_opacity_mode" + "name": "o_opacity_mode" } }, { - "id": "alphaSource", + "name": "alphaSource", "displayName": "Alpha Source", "description": "Source texture of alpha value. 0:Packed, 1:Split, 2:None", "type": "Uint", "defaultValue": 0, "connection": { "type": "ShaderOption", - "id": "o_opacity_source" + "name": "o_opacity_source" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture Map", "description": "Texture map for defining surface opacity.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_opacityMap" + "name": "m_opacityMap" } }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Factor for cutout threshold and blending", "type": "Float", @@ -330,11 +330,11 @@ "defaultValue": 0.5, "connection": { "type": "ShaderInput", - "id": "m_opacityFactor" + "name": "m_opacityFactor" } }, { - "id": "doubleSided", + "name": "doubleSided", "displayName": "Double-sided", "description": "Whether to render back-faces or just front-faces.", "type": "Bool" @@ -342,14 +342,14 @@ ], "uv": [ { - "id": "center", + "name": "center", "displayName": "Center", "description": "Center point for scaling and rotation transformations.", "type": "vector2", "defaultValue": [0.0, 0.0] }, { - "id": "tileU", + "name": "tileU", "displayName": "Tile U", "description": "Scales texture coordinates in V.", "type": "float", @@ -357,7 +357,7 @@ "step": 0.1 }, { - "id": "tileV", + "name": "tileV", "displayName": "Tile V", "description": "Scales texture coordinates in V.", "type": "float", @@ -365,7 +365,7 @@ "step": 0.1 }, { - "id": "offsetU", + "name": "offsetU", "displayName": "Offset U", "description": "Offsets texture coordinates in the U direction.", "type": "float", @@ -374,7 +374,7 @@ "max": 1.0 }, { - "id": "offsetV", + "name": "offsetV", "displayName": "Offset V", "description": "Offsets texture coordinates in the V direction.", "type": "float", @@ -383,7 +383,7 @@ "max": 1.0 }, { - "id": "rotateDegrees", + "name": "rotateDegrees", "displayName": "Rotate", "description": "Rotates the texture coordinates (degrees).", "type": "float", @@ -393,7 +393,7 @@ "step": 1.0 }, { - "id": "scale", + "name": "scale", "displayName": "Scale", "description": "Scales texture coordinates in both U and V.", "type": "float", @@ -403,29 +403,29 @@ ], "emissive": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Enable the emissive group", "type":"Bool", "defaultValue": false, "connection": { "type": "ShaderOption", - "id": "o_emissiveEnabled" + "name": "o_emissiveEnabled" } }, { - "id": "color", + "name": "color", "displayName": "Color", "description": "Color is displayed as sRGB but the values are stored as linear color.", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_emissiveColor" + "name": "m_emissiveColor" } }, { - "id": "intensity", + "name": "intensity", "displayName": "Intensity", "description": "The amount of energy emitted, in EV100 unit", "type": "Float", @@ -434,33 +434,33 @@ "max": 5 }, { - "id": "useTexture", + "name": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture map.", "type": "Bool", "defaultValue": false }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture Map", "description": "Texture map for defining emissive area.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_emissiveMap" + "name": "m_emissiveMap" } } ], "parallax": [ { - "id": "enable", + "name": "enable", "displayName": "Enable", "description": "Whether to enable the parallax feature.", "type": "Bool", "defaultValue": false }, { - "id": "factor", + "name": "factor", "displayName": "Factor", "description": "Strength factor for scaling the depth values", "type": "Float", @@ -469,39 +469,39 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_heightmapScale" + "name": "m_heightmapScale" } }, { - "id": "textureMap", + "name": "textureMap", "displayName": "Texture Map", "description": "Depthmap to create parallax effect.", "type": "Image", "connection": { "type": "ShaderInput", - "id": "m_heightmap" + "name": "m_heightmap" } }, { - "id": "algorithm", + "name": "algorithm", "displayName": "Algorithm", "description": "Select the algorithm to use for parallax mapping. 0: Basic, 1:Steep, 2:POM, 3:Relief, 4:Contact refinement", "type": "Uint", "defaultValue": 0, "connection":{ "type": "ShaderOption", - "id": "o_parallax_algorithm" + "name": "o_parallax_algorithm" } }, { - "id": "quality", + "name": "quality", "displayName": "Quality", "description": "Quality of parallax mapping. 0:Low, 1:Medium, 2:High, 3:Ultra", "type": "Uint", "defaultValue": 0, "connection":{ "type": "ShaderOption", - "id": "o_parallax_quality" + "name": "o_parallax_quality" } } ] diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype index 59b7af8439..74246f85db 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype @@ -5,7 +5,7 @@ "properties": { "settings": [ { - "id": "opacity", + "name": "opacity", "displayName": "Opacity", "description": "Opacity of the shadow effect.", "type": "Float", @@ -14,17 +14,17 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_opacity" + "name": "m_opacity" } }, { - "id": "shadeAll", + "name": "shadeAll", "displayName": "Shade All", "description": "Shades the entire geometry with the shadow color, not just what's in shadow. For debugging.", "type": "Bool", "connection": { "type": "ShaderOption", - "id": "o_shadeAll" + "name": "o_shadeAll" } } ] diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp index 5ddeb08ef8..1c13a5f133 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp @@ -46,7 +46,7 @@ namespace AZ { AssetBuilderSDK::AssetBuilderDesc materialBuilderDescriptor; materialBuilderDescriptor.m_name = JobKey; - materialBuilderDescriptor.m_version = 107; // ATOM-14918 + materialBuilderDescriptor.m_version = 108; // ATOM-5041 materialBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.material", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); materialBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.materialtype", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); materialBuilderDescriptor.m_busId = azrtti_typeid(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp index 578e69e5ca..b8b55a9fd5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp @@ -27,7 +27,6 @@ namespace AZ { namespace Field { - static constexpr const char id[] = "id"; // legacy field, replaced by "name" static constexpr const char name[] = "name"; static constexpr const char displayName[] = "displayName"; static constexpr const char description[] = "description"; @@ -47,7 +46,6 @@ namespace AZ static const AZStd::string_view AcceptedFields[] = { - Field::id, Field::name, Field::displayName, Field::description, @@ -220,10 +218,7 @@ namespace AZ } } - // Field::id is the legacy field, replaced by Field::name. If both are present, Field::name will take priority. - result.Combine(ContinueLoadingFromJsonObjectField(&property->m_name, azrtti_typeid(), inputValue, Field::id, context)); result.Combine(ContinueLoadingFromJsonObjectField(&property->m_name, azrtti_typeid(), inputValue, Field::name, context)); - result.Combine(ContinueLoadingFromJsonObjectField(&property->m_displayName, azrtti_typeid(), inputValue, Field::displayName, context)); result.Combine(ContinueLoadingFromJsonObjectField(&property->m_description, azrtti_typeid(), inputValue, Field::description, context)); result.Combine(ContinueLoadingFromJsonObjectField(&property->m_dataType, azrtti_typeid(), inputValue, Field::type, context)); 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 1a6c7868a3..a13a8df16e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -50,9 +50,8 @@ namespace AZ else if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(1) + ->Version(2) ->Field("type", &PropertyConnection::m_type) - ->Field("id", &PropertyConnection::m_fieldName) // The old reflection, replaced by "name" ->Field("name", &PropertyConnection::m_fieldName) ->Field("shaderIndex", &PropertyConnection::m_shaderIndex) ; @@ -60,8 +59,7 @@ namespace AZ serializeContext->RegisterGenericType(); serializeContext->Class() - ->Version(1) - ->Field("id", &GroupDefinition::m_name) // The old reflection, replaced by "name" + ->Version(2) ->Field("name", &GroupDefinition::m_name) ->Field("displayName", &GroupDefinition::m_displayName) ->Field("description", &GroupDefinition::m_description) diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp index ce842d385d..5705c3416a 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp @@ -46,7 +46,7 @@ namespace JsonSerializationTests AZStd::shared_ptr CreatePartialDefaultInstance() override { auto result = AZStd::make_shared(); - result->m_nameId = "testProperty"; + result->m_name = "testProperty"; result->m_dataType = AZ::RPI::MaterialPropertyDataType::Float; result->m_step = 1.0f; result->m_value = 0.0f; @@ -57,7 +57,7 @@ namespace JsonSerializationTests { return R"( { - "id": "testProperty", + "name": "testProperty", "type": "Float", "step": 1.0 })"; @@ -66,7 +66,7 @@ namespace JsonSerializationTests AZStd::shared_ptr CreateFullySetInstance() override { auto result = AZStd::make_shared(); - result->m_nameId = "testProperty"; + result->m_name = "testProperty"; result->m_description = "description"; result->m_displayName = "display_name"; result->m_dataType = AZ::RPI::MaterialPropertyDataType::Float; @@ -87,7 +87,7 @@ namespace JsonSerializationTests { return R"( { - "id": "testProperty", + "name": "testProperty", "displayName": "display_name", "description": "description", "type": "Float", @@ -101,7 +101,7 @@ namespace JsonSerializationTests "connection": { "type": "ShaderOption", - "id": "o_foo", + "name": "o_foo", "shaderIndex": 2 }, "enumIsUv": true @@ -135,7 +135,7 @@ namespace JsonSerializationTests const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& lhs, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& rhs) override { - if (lhs.m_nameId != rhs.m_nameId) { return false; } + if (lhs.m_name != rhs.m_name) { return false; } if (lhs.m_description != rhs.m_description) { return false; } if (lhs.m_displayName != rhs.m_displayName) { return false; } if (lhs.m_dataType != rhs.m_dataType) { return false; } @@ -153,7 +153,7 @@ namespace JsonSerializationTests auto& leftConnection = lhs.m_outputConnections[i]; auto& rightConnection = rhs.m_outputConnections[i]; if (leftConnection.m_type != rightConnection.m_type) { return false; } - if (leftConnection.m_nameId != rightConnection.m_nameId) { return false; } + if (leftConnection.m_fieldName != rightConnection.m_fieldName) { return false; } if (leftConnection.m_shaderIndex != rightConnection.m_shaderIndex) { return false; } } return true; @@ -202,7 +202,7 @@ namespace UnitTest { const AZStd::string inputJson = R"( { - "id": "testProperty", + "name": "testProperty", "displayName": "Test Property", "description": "This is a property description", "type": "Float" @@ -216,12 +216,12 @@ namespace UnitTest EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, loadResult.m_jsonResultCode.GetProcessing()); EXPECT_EQ(AZ::JsonSerializationResult::Outcomes::PartialDefaults, loadResult.m_jsonResultCode.GetOutcome()); - EXPECT_EQ("testProperty", propertyData.m_nameId); + EXPECT_EQ("testProperty", propertyData.m_name); EXPECT_EQ("Test Property", propertyData.m_displayName); EXPECT_EQ("This is a property description", propertyData.m_description); EXPECT_EQ(MaterialPropertyDataType::Float, propertyData.m_dataType); - EXPECT_TRUE(loadResult.ContainsMessage("/id", "Success")); + EXPECT_TRUE(loadResult.ContainsMessage("/name", "Success")); EXPECT_TRUE(loadResult.ContainsMessage("/displayName", "Success")); EXPECT_TRUE(loadResult.ContainsMessage("/description", "Success")); EXPECT_TRUE(loadResult.ContainsMessage("/type", "Success")); @@ -237,7 +237,7 @@ namespace UnitTest // Note we are keeping id and type because they are required fields const AZStd::string inputJson = R"( { - "id": "testProperty", + "name": "testProperty", "type": "Float" } )"; @@ -252,7 +252,7 @@ namespace UnitTest EXPECT_TRUE(propertyData.m_displayName.empty()); EXPECT_TRUE(propertyData.m_description.empty()); - EXPECT_TRUE(loadResult.ContainsMessage("/id", "Success")); + EXPECT_TRUE(loadResult.ContainsMessage("/name", "Success")); EXPECT_TRUE(loadResult.ContainsMessage("/type", "Success")); EXPECT_FALSE(loadResult.ContainsOutcome(JsonSerializationResult::Outcomes::Skipped)); @@ -280,7 +280,7 @@ namespace UnitTest { const AZStd::string inputJson = R"( { - "id": "testProperty", + "name": "testProperty", "type": "foo" } )"; @@ -294,7 +294,7 @@ namespace UnitTest EXPECT_EQ(AZ::RPI::MaterialPropertyDataType::Invalid, propertyData.m_dataType); - EXPECT_TRUE(loadResult.ContainsMessage("/id", "Success")); + EXPECT_TRUE(loadResult.ContainsMessage("/name", "Success")); EXPECT_TRUE(loadResult.ContainsMessage("/type", "Enum value could not read")); } @@ -303,7 +303,7 @@ namespace UnitTest const AZStd::string inputJson = R"( [ { - "id": "testProperty1", + "name": "testProperty1", "type": "Float", "defaultValue": 0.5, "min": 0.1, @@ -313,7 +313,7 @@ namespace UnitTest "step": 0.05 }, { - "id": "testProperty2", + "name": "testProperty2", "type": "Int", "defaultValue": -1, "min": -5, @@ -323,7 +323,7 @@ namespace UnitTest "step": 1 }, { - "id": "testProperty3", + "name": "testProperty3", "type": "UInt", "defaultValue": 4294901761, "min": 4294901760, @@ -368,7 +368,7 @@ namespace UnitTest for (int i = 0; i < propertyData.size(); ++i) { AZStd::string prefix = AZStd::string::format("/%d", i); - EXPECT_TRUE(loadResult.ContainsMessage(prefix + "/id", "Success")); + EXPECT_TRUE(loadResult.ContainsMessage(prefix + "/name", "Success")); EXPECT_TRUE(loadResult.ContainsMessage(prefix + "/type", "Success")); EXPECT_TRUE(loadResult.ContainsMessage(prefix + "/defaultValue", "Success")); EXPECT_TRUE(loadResult.ContainsMessage(prefix + "/min", "Success")); @@ -388,19 +388,19 @@ namespace UnitTest const AZStd::string inputJson = R"( [ { - "id": "testProperty1", + "name": "testProperty1", "displayName": "Test Property 1", "description": "Test", "type": "Float" }, { - "id": "testProperty2", + "name": "testProperty2", "displayName": "Test Property 2", "description": "Test", "type": "Int" }, { - "id": "testProperty3", + "name": "testProperty3", "displayName": "Test Property 3", "description": "Test", "type": "UInt" @@ -443,13 +443,13 @@ namespace UnitTest const AZStd::string inputJson = R"( [ { - "id": "testProperty1", + "name": "testProperty1", "type": "Vector2", "vectorLabels": ["U", "V"], "defaultValue": [0.6, 0.5] }, { - "id": "testProperty2", + "name": "testProperty2", "type": "Vector4", "vectorLabels": ["A", "B", "C", "D"], "defaultValue": [0.3, 0.4, 0.5, 0.6] @@ -485,21 +485,21 @@ namespace UnitTest const AZStd::string inputJson = R"( [ { - "id": "visibilityIsDefault", + "name": "visibilityIsDefault", "type": "Float" }, { - "id": "visibilityIsEditable", + "name": "visibilityIsEditable", "type": "Float", "visibility": "Enabled" }, { - "id": "visibilityIsDisabled", + "name": "visibilityIsDisabled", "type": "Float", "visibility": "Disabled" }, { - "id": "visibilityIsHidden", + "name": "visibilityIsHidden", "type": "Float", "visibility": "Hidden" } @@ -509,20 +509,20 @@ namespace UnitTest const AZStd::string expectedOutputJson = R"( [ { - "id": "visibilityIsDefault", + "name": "visibilityIsDefault", "type": "Float" }, { - "id": "visibilityIsEditable", + "name": "visibilityIsEditable", "type": "Float" }, { - "id": "visibilityIsDisabled", + "name": "visibilityIsDisabled", "type": "Float", "visibility": "Disabled" }, { - "id": "visibilityIsHidden", + "name": "visibilityIsHidden", "type": "Float", "visibility": "Hidden" } @@ -552,7 +552,7 @@ namespace UnitTest const AZStd::string inputJson = R"( [ { - "id": "testProperty1", + "name": "testProperty1", "type": "Float", "defaultValue": true, "min": -1, @@ -560,7 +560,7 @@ namespace UnitTest "step": "1" }, { - "id": "testProperty2", + "name": "testProperty2", "type": "Int", "defaultValue": true, "min": -1.5, @@ -568,7 +568,7 @@ namespace UnitTest "step": "1" }, { - "id": "testProperty3", + "name": "testProperty3", "type": "UInt", "defaultValue": "4294963200", "min": true, @@ -610,32 +610,32 @@ namespace UnitTest const AZStd::string inputJson = R"( [ { - "id": "testProperty1", + "name": "testProperty1", "type": "Bool", "defaultValue": true }, { - "id": "testProperty2", + "name": "testProperty2", "type": "Vector2", "defaultValue": [0.1, 0.2] }, { - "id": "testProperty3", + "name": "testProperty3", "type": "Vector3", "defaultValue": [0.3, 0.4, 0.5] }, { - "id": "testProperty4", + "name": "testProperty4", "type": "Vector4", "defaultValue": [0.6, 0.5, 0.8, 0.4] }, { - "id": "testProperty5", + "name": "testProperty5", "type": "Color", "defaultValue": [0.1, 0.2, 0.3] }, { - "id": "testProperty6", + "name": "testProperty6", "type": "Image", "defaultValue": "Default.png" } @@ -669,7 +669,7 @@ namespace UnitTest for (int i = 0; i < propertyData.size(); ++i) { AZStd::string prefix = AZStd::string::format("/%d", i); - EXPECT_TRUE(loadResult.ContainsMessage(prefix + "/id", "Success")); + EXPECT_TRUE(loadResult.ContainsMessage(prefix + "/name", "Success")); EXPECT_TRUE(loadResult.ContainsMessage(prefix + "/type", "Success")); EXPECT_TRUE(loadResult.ContainsMessage(prefix + "/defaultValue", "Success")); } @@ -684,27 +684,27 @@ namespace UnitTest const AZStd::string inputJson = R"( [ { - "id": "testProperty1", + "name": "testProperty1", "type": "Bool" }, { - "id": "testProperty2", + "name": "testProperty2", "type": "Vector2" }, { - "id": "testProperty3", + "name": "testProperty3", "type": "Vector3" }, { - "id": "testProperty4", + "name": "testProperty4", "type": "Vector4" }, { - "id": "testProperty5", + "name": "testProperty5", "type": "Color" }, { - "id": "testProperty6", + "name": "testProperty6", "type": "Image" } ] @@ -745,27 +745,27 @@ namespace UnitTest const AZStd::string inputJson = R"( [ { - "id": "testProperty1", + "name": "testProperty1", "type": "Bool", "defaultValue": 1 }, { - "id": "testProperty2", + "name": "testProperty2", "type": "Vector2", "defaultValue": { "x": 0.4, "y": 0.1 } }, { - "id": "testProperty3", + "name": "testProperty3", "type": "Vector3", "defaultValue": { "x": 0.4, "y": 0.1, "z": 0.5 } }, { - "id": "testProperty4", + "name": "testProperty4", "type": "Vector4", "defaultValue": { "x": 0.4, "y": 0.1, "z": 0.5, "w": 0.6 } }, { - "id": "testProperty5", + "name": "testProperty5", "type": "Color", "defaultValue": { "hex": "FF00FF" } } @@ -800,11 +800,11 @@ namespace UnitTest { const AZStd::string inputJson = R"( { - "id": "testProperty", + "name": "testProperty", "type": "Float", "connection": { "type": "ShaderOption", - "id": "o_foo", + "name": "o_foo", "shaderIndex": 2 } } @@ -818,11 +818,11 @@ namespace UnitTest EXPECT_EQ(1, propertyData.m_outputConnections.size()); EXPECT_EQ(MaterialPropertyOutputType::ShaderOption, propertyData.m_outputConnections[0].m_type); - EXPECT_EQ("o_foo", propertyData.m_outputConnections[0].m_nameId); + EXPECT_EQ("o_foo", propertyData.m_outputConnections[0].m_fieldName); EXPECT_EQ(2, propertyData.m_outputConnections[0].m_shaderIndex); EXPECT_TRUE(loadResult.ContainsMessage("/connection/type", "Success")); - EXPECT_TRUE(loadResult.ContainsMessage("/connection/id", "Success")); + EXPECT_TRUE(loadResult.ContainsMessage("/connection/name", "Success")); EXPECT_TRUE(loadResult.ContainsMessage("/connection/shaderIndex", "Success")); EXPECT_FALSE(loadResult.ContainsOutcome(JsonSerializationResult::Outcomes::Skipped)); @@ -833,17 +833,17 @@ namespace UnitTest { const AZStd::string inputJson = R"( { - "id": "testProperty", + "name": "testProperty", "type": "Float", "connection": [ { "type": "ShaderInput", - "id": "o_foo", + "name": "o_foo", "shaderIndex": 2 }, { "type": "ShaderOption", - "id": "o_bar", + "name": "o_bar", "shaderIndex": 1 } ] @@ -858,18 +858,18 @@ namespace UnitTest EXPECT_EQ(2, propertyData.m_outputConnections.size()); EXPECT_EQ(MaterialPropertyOutputType::ShaderInput, propertyData.m_outputConnections[0].m_type); - EXPECT_EQ("o_foo", propertyData.m_outputConnections[0].m_nameId); + EXPECT_EQ("o_foo", propertyData.m_outputConnections[0].m_fieldName); EXPECT_EQ(2, propertyData.m_outputConnections[0].m_shaderIndex); EXPECT_EQ(MaterialPropertyOutputType::ShaderOption, propertyData.m_outputConnections[1].m_type); - EXPECT_EQ("o_bar", propertyData.m_outputConnections[1].m_nameId); + EXPECT_EQ("o_bar", propertyData.m_outputConnections[1].m_fieldName); EXPECT_EQ(1, propertyData.m_outputConnections[1].m_shaderIndex); EXPECT_TRUE(loadResult.ContainsMessage("/connection/0/type", "Success")); - EXPECT_TRUE(loadResult.ContainsMessage("/connection/0/id", "Success")); + EXPECT_TRUE(loadResult.ContainsMessage("/connection/0/name", "Success")); EXPECT_TRUE(loadResult.ContainsMessage("/connection/0/shaderIndex", "Success")); EXPECT_TRUE(loadResult.ContainsMessage("/connection/1/type", "Success")); - EXPECT_TRUE(loadResult.ContainsMessage("/connection/1/id", "Success")); + EXPECT_TRUE(loadResult.ContainsMessage("/connection/1/name", "Success")); EXPECT_TRUE(loadResult.ContainsMessage("/connection/1/shaderIndex", "Success")); EXPECT_FALSE(loadResult.ContainsOutcome(JsonSerializationResult::Outcomes::Skipped)); @@ -881,12 +881,12 @@ namespace UnitTest // "conection" is misspelled const AZStd::string inputJson = R"( { - "id": "testProperty", + "name": "testProperty", "type": "Float", "conection": [ { "type": "ShaderInput", - "id": "o_foo", + "name": "o_foo", "shaderIndex": 2 } ] @@ -899,7 +899,7 @@ namespace UnitTest EXPECT_EQ(AZ::JsonSerializationResult::Tasks::ReadField, loadResult.m_jsonResultCode.GetTask()); EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, loadResult.m_jsonResultCode.GetProcessing()); - EXPECT_EQ(propertyData.m_nameId, "testProperty"); + EXPECT_EQ(propertyData.m_name, "testProperty"); EXPECT_EQ(propertyData.m_dataType, MaterialPropertyDataType::Float); EXPECT_EQ(propertyData.m_outputConnections.size(), 0); @@ -911,13 +911,13 @@ namespace UnitTest // "shadrIndex" is misspelled const AZStd::string inputJson = R"( { - "id": "testProperty", + "name": "testProperty", "type": "Float", "connection": [ { "type": "ShaderInput", "shadrIndex": 2, - "id": "o_foo" + "name": "o_foo" } ] } @@ -929,10 +929,10 @@ namespace UnitTest EXPECT_EQ(AZ::JsonSerializationResult::Tasks::ReadField, loadResult.m_jsonResultCode.GetTask()); EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, loadResult.m_jsonResultCode.GetProcessing()); - EXPECT_EQ(propertyData.m_nameId, "testProperty"); + EXPECT_EQ(propertyData.m_name, "testProperty"); EXPECT_EQ(propertyData.m_dataType, MaterialPropertyDataType::Float); EXPECT_EQ(propertyData.m_outputConnections.size(), 1); - EXPECT_EQ(propertyData.m_outputConnections[0].m_nameId, "o_foo"); + EXPECT_EQ(propertyData.m_outputConnections[0].m_fieldName, "o_foo"); EXPECT_EQ(propertyData.m_outputConnections[0].m_type, MaterialPropertyOutputType::ShaderInput); EXPECT_EQ(propertyData.m_outputConnections[0].m_shaderIndex, -1); diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp index 13effd4eaf..dd3b3b2711 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp @@ -205,25 +205,25 @@ namespace UnitTest " \"propertyLayout\": { \n" " \"version\": 1, \n" " \"groups\": [ \n" - " { \"id\": \"groupA\" }, \n" - " { \"id\": \"groupB\" }, \n" - " { \"id\": \"groupC\" } \n" + " { \"name\": \"groupA\" }, \n" + " { \"name\": \"groupB\" }, \n" + " { \"name\": \"groupC\" } \n" " ], \n" " \"properties\": { \n" " \"groupA\": [ \n" - " {\"id\": \"MyBool\", \"type\": \"bool\"}, \n" - " {\"id\": \"MyInt\", \"type\": \"int\"}, \n" - " {\"id\": \"MyUInt\", \"type\": \"uint\"} \n" + " {\"name\": \"MyBool\", \"type\": \"bool\"}, \n" + " {\"name\": \"MyInt\", \"type\": \"int\"}, \n" + " {\"name\": \"MyUInt\", \"type\": \"uint\"} \n" " ], \n" " \"groupB\": [ \n" - " {\"id\": \"MyFloat\", \"type\": \"float\"}, \n" - " {\"id\": \"MyFloat2\", \"type\": \"vector2\"}, \n" - " {\"id\": \"MyFloat3\", \"type\": \"vector3\"} \n" + " {\"name\": \"MyFloat\", \"type\": \"float\"}, \n" + " {\"name\": \"MyFloat2\", \"type\": \"vector2\"}, \n" + " {\"name\": \"MyFloat3\", \"type\": \"vector3\"} \n" " ], \n" " \"groupC\": [ \n" - " {\"id\": \"MyFloat4\", \"type\": \"vector4\"}, \n" - " {\"id\": \"MyColor\", \"type\": \"color\"}, \n" - " {\"id\": \"MyImage\", \"type\": \"image\"} \n" + " {\"name\": \"MyFloat4\", \"type\": \"vector4\"}, \n" + " {\"name\": \"MyColor\", \"type\": \"color\"}, \n" + " {\"name\": \"MyImage\", \"type\": \"image\"} \n" " ] \n" " } \n" " } \n" @@ -271,7 +271,7 @@ namespace UnitTest "properties": { "general": [ { - "id": "testColor", + "name": "testColor", "type": "color" } ] @@ -381,7 +381,7 @@ namespace UnitTest "properties": { "general": [ { - "id": "testColor", + "name": "testColor", "type": "color" } ] @@ -427,7 +427,7 @@ namespace UnitTest "properties": { "general": [ { - "id": "testColor", + "name": "testColor", "type": "color" } ] diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp index 179dc7c966..c37943f79c 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp @@ -510,7 +510,7 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ TestShaderFilename }); MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_nameId = "MyBool"; + propertySource.m_name = "MyBool"; propertySource.m_displayName = "My Bool"; propertySource.m_description = "This is a bool"; propertySource.m_dataType = MaterialPropertyDataType::Bool; @@ -536,7 +536,7 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ TestShaderFilename }); MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_nameId = "MyFloat"; + propertySource.m_name = "MyFloat"; propertySource.m_displayName = "My Float"; propertySource.m_description = "This is a float"; propertySource.m_min = 0.0f; @@ -566,7 +566,7 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ TestShaderFilename }); MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_nameId = "MyImage"; + propertySource.m_name = "MyImage"; propertySource.m_displayName = "My Image"; propertySource.m_description = "This is an image"; propertySource.m_dataType = MaterialPropertyDataType::Image; @@ -591,7 +591,7 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_nameId = "MyInt"; + propertySource.m_name = "MyInt"; propertySource.m_displayName = "My Integer"; propertySource.m_dataType = MaterialPropertyDataType::Int; propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{MaterialPropertyOutputType::ShaderOption, AZStd::string("o_foo"), 0}); @@ -614,7 +614,7 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_nameId = "MyInt"; + propertySource.m_name = "MyInt"; propertySource.m_dataType = MaterialPropertyDataType::Int; propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{MaterialPropertyOutputType::ShaderOption, AZStd::string("DoesNotExist"), 0}); sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); @@ -633,7 +633,7 @@ namespace UnitTest MaterialTypeSourceData::PropertyDefinition propertySource; propertySource.m_dataType = MaterialPropertyDataType::Int; - propertySource.m_nameId = "a"; + propertySource.m_name = "a"; sourceData.m_propertyLayout.m_properties["not a valid name because it has spaces"].push_back(propertySource); // Expected errors: @@ -654,7 +654,7 @@ namespace UnitTest MaterialTypeSourceData::PropertyDefinition propertySource; propertySource.m_dataType = MaterialPropertyDataType::Int; - propertySource.m_nameId = "not a valid name because it has spaces"; + propertySource.m_name = "not a valid name because it has spaces"; sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); // Expected errors: @@ -674,7 +674,7 @@ namespace UnitTest MaterialTypeSourceData::PropertyDefinition propertySource; propertySource.m_dataType = MaterialPropertyDataType::Int; - propertySource.m_nameId = "a"; + propertySource.m_name = "a"; sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); @@ -738,7 +738,7 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ "shaderC.shader" }); MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_nameId = "MyInt"; + propertySource.m_name = "MyInt"; propertySource.m_displayName = "Integer"; propertySource.m_description = "Integer property that is connected to multiple shader settings"; propertySource.m_dataType = MaterialPropertyDataType::Int; @@ -797,7 +797,7 @@ namespace UnitTest MaterialTypeSourceData sourceData; MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_nameId = "NonAliasFloat"; + propertySource.m_name = "NonAliasFloat"; propertySource.m_displayName = "Non-Alias Float"; propertySource.m_description = "This float is processed by a functor, not with a direct alias"; propertySource.m_dataType = MaterialPropertyDataType::Float; @@ -842,13 +842,13 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_nameId = "EnableSpecialPassA"; + propertySource.m_name = "EnableSpecialPassA"; propertySource.m_displayName = "Enable Special Pass"; propertySource.m_description = "This is a bool to enable an extra shader/pass"; propertySource.m_dataType = MaterialPropertyDataType::Bool; // Note that we don't fill propertySource.m_outputConnections because this is not a direct-connected property sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); - propertySource.m_nameId = "EnableSpecialPassB"; + propertySource.m_name = "EnableSpecialPassB"; sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); sourceData.m_materialFunctorSourceData.push_back( @@ -902,7 +902,7 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_nameId = "MyProperty"; + propertySource.m_name = "MyProperty"; propertySource.m_dataType = MaterialPropertyDataType::Bool; // Note that we don't fill propertySource.m_outputConnections because this is not a direct-connected property sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); @@ -938,7 +938,7 @@ namespace UnitTest auto addProperty = [&sourceData](MaterialPropertyDataType dateType, const char* propertyName, const char* srgConstantName, const AZ::RPI::MaterialPropertyValue& value) { MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_nameId = propertyName; + propertySource.m_name = propertyName; propertySource.m_dataType = dateType; propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string(srgConstantName) }); propertySource.m_value = value; @@ -982,12 +982,12 @@ namespace UnitTest "version": 2, "groups": [ { - "id": "groupA", + "name": "groupA", "displayName": "Property Group A", "description": "Description of property group A" }, { - "id": "groupB", + "name": "groupB", "displayName": "Property Group B", "description": "Description of property group B" } @@ -995,12 +995,12 @@ namespace UnitTest "properties": { "groupA": [ { - "id": "foo", + "name": "foo", "type": "Bool", "defaultValue": true }, { - "id": "bar", + "name": "bar", "type": "Image", "defaultValue": "Default.png", "visibility": "Hidden" @@ -1008,12 +1008,12 @@ namespace UnitTest ], "groupB": [ { - "id": "foo", + "name": "foo", "type": "Float", "defaultValue": 0.5 }, { - "id": "bar", + "name": "bar", "type": "Color", "defaultValue": [0.5, 0.5, 0.5], "visibility": "Disabled" @@ -1075,10 +1075,10 @@ namespace UnitTest EXPECT_EQ(material.m_propertyLayout.m_properties.size(), 2); EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"].size(), 2); EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"].size(), 2); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_nameId, "foo"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_nameId, "bar"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_nameId, "foo"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_nameId, "bar"); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_name, "foo"); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_name, "bar"); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_name, "foo"); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_name, "bar"); EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_dataType, MaterialPropertyDataType::Bool); EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_dataType, MaterialPropertyDataType::Image); EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_dataType, MaterialPropertyDataType::Float); @@ -1127,7 +1127,7 @@ namespace UnitTest "version": 2, "groups": [ { - "id": "general", + "name": "general", "displayName": "General", "description": "" } @@ -1135,12 +1135,12 @@ namespace UnitTest "properties": { "general": [ { - "id": "absolute", + "name": "absolute", "type": "Image", "defaultValue": "%s" }, { - "id": "relative", + "name": "relative", "type": "Image", "defaultValue": "%s" } diff --git a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype index 0b62638c5a..00f11663f7 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype +++ b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype @@ -4,12 +4,12 @@ "version": 3, "groups": [ { - "id": "shape", + "name": "shape", "displayName": "Shape", "description": "Properties for configuring size, shape, and position of the bricks." }, { - "id": "appearance", + "name": "appearance", "displayName": "Appearance", "description": "Properties for configuring the appearance of the bricks and grout lines." } @@ -17,7 +17,7 @@ "properties": { "shape": [ { - "id": "brickWidth", + "name": "brickWidth", "displayName": "Brick Width", "description": "The width of each brick.", "type": "Float", @@ -27,11 +27,11 @@ "step": 0.001, "connection": { "type": "ShaderInput", - "id": "m_brickWidth" + "name": "m_brickWidth" } }, { - "id": "brickHeight", + "name": "brickHeight", "displayName": "Brick Height", "description": "The height of each brick.", "type": "Float", @@ -41,11 +41,11 @@ "step": 0.001, "connection": { "type": "ShaderInput", - "id": "m_brickHeight" + "name": "m_brickHeight" } }, { - "id": "brickOffset", + "name": "brickOffset", "displayName": "Offset", "description": "The offset of each stack of bricks as a percentage of brick width.", "type": "Float", @@ -54,11 +54,11 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_brickOffset" + "name": "m_brickOffset" } }, { - "id": "lineWidth", + "name": "lineWidth", "displayName": "Line Width", "description": "The width of the grout lines.", "type": "Float", @@ -68,11 +68,11 @@ "step": 0.0001, "connection": { "type": "ShaderInput", - "id": "m_lineWidth" + "name": "m_lineWidth" } }, { - "id": "lineDepth", + "name": "lineDepth", "displayName": "Line Depth", "description": "The depth of the grout lines.", "type": "Float", @@ -81,34 +81,34 @@ "softMax": 0.02, "connection": { "type": "ShaderInput", - "id": "m_lineDepth" + "name": "m_lineDepth" } } ], "appearance": [ { - "id": "noiseTexture", + "name": "noiseTexture", "type": "Image", "defaultValue": "TestData/Textures/noise512.png", "visibility": "Hidden", "connection": { "type": "ShaderInput", - "id": "m_noise" + "name": "m_noise" } }, { - "id": "brickColor", + "name": "brickColor", "displayName": "Brick Color", "description": "The color of the bricks.", "type": "Color", "defaultValue": [1.0,1.0,1.0], "connection": { "type": "ShaderInput", - "id": "m_brickColor" + "name": "m_brickColor" } }, { - "id": "brickColorNoise", + "name": "brickColorNoise", "displayName": "Brick Color Noise", "description": "Scale the variation of brick color.", "type": "Float", @@ -117,22 +117,22 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_brickNoiseFactor" + "name": "m_brickNoiseFactor" } }, { - "id": "lineColor", + "name": "lineColor", "displayName": "Line Color", "description": "The color of the grout lines.", "type": "Color", "defaultValue": [0.5,0.5,0.5], "connection": { "type": "ShaderInput", - "id": "m_lineColor" + "name": "m_lineColor" } }, { - "id": "lineColorNoise", + "name": "lineColorNoise", "displayName": "Line Color Noise", "description": "Scale the variation of grout line color.", "type": "Float", @@ -141,11 +141,11 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_lineNoiseFactor" + "name": "m_lineNoiseFactor" } }, { - "id": "brickColorBleed", + "name": "brickColorBleed", "displayName": "Brick Color Bleed", "description": "Distance into the grout line that the brick color will continue.", "type": "Float", @@ -154,11 +154,11 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_brickColorBleed" + "name": "m_brickColorBleed" } }, { - "id": "ao", + "name": "ao", "displayName": "Ambient Occlusion", "description": "The strength of baked ambient occlusion in the grout lines.", "type": "Float", @@ -167,7 +167,7 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_aoFactor" + "name": "m_aoFactor" } } ] diff --git a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype index fb2b8523e1..81ebd63c28 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype +++ b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype @@ -4,24 +4,24 @@ "version": 3, "groups": [ { - "id": "settings", + "name": "settings", "displayName": "Settings" } ], "properties": { "settings": [ { - "id": "color", + "name": "color", "displayName": "Color", "type": "Color", "defaultValue": [ 1.0, 1.0, 1.0 ], "connection": { "type": "ShaderInput", - "id": "m_baseColor" + "name": "m_baseColor" } }, { - "id": "metallic", + "name": "metallic", "displayName": "Metallic", "type": "Float", "defaultValue": 0.0, @@ -29,11 +29,11 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_metallic" + "name": "m_metallic" } }, { - "id": "roughness", + "name": "roughness", "displayName": "Roughness", "type": "Float", "defaultValue": 1.0, @@ -41,7 +41,7 @@ "max": 1.0, "connection": { "type": "ShaderInput", - "id": "m_roughness" + "name": "m_roughness" } } ] From acd7d3c27766d929e46acf09479437f067065483 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Sep 2021 12:43:50 +0100 Subject: [PATCH 029/115] Change all nomenclature to Activate/Deactivate for consistency. Signed-off-by: John --- .../API/ViewportEditorModeTrackerInterface.h | 8 +-- ...ViewportEditorModeTrackerNotificationBus.h | 8 +-- .../ViewportEditorModeTracker.cpp | 22 +++---- .../ViewportEditorModeTracker.h | 9 ++- .../Viewport/ViewportEditorModeTests.cpp | 58 +++++++++---------- 5 files changed, 52 insertions(+), 53 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index ae4f3424eb..bcc8afbe6a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -22,12 +22,12 @@ namespace AzToolsFramework virtual ~ViewportEditorModeTrackerInterface() = default; - //! Registers the specified editor mode as active for the specified viewport. - virtual AZ::Outcome RegisterMode( + //! Activates the specified editor mode for the specified viewport. + virtual AZ::Outcome ActivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; - //! Unregisters the specified editor mode as active for the specified viewport. - virtual AZ::Outcome UnregisterMode( + //! Deactivates the specified editor mode for the specified viewport. + virtual AZ::Outcome DeactivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index caa762241c..d4e5dd4fbb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -52,13 +52,13 @@ namespace AzToolsFramework using BusIdType = ViewportEditorModeInfo::IdType; ////////////////////////////////////////////////////////////////////////// - //! Notifies subscribers of the a given viewport to the entering of the specified editor mode. - virtual void OnEditorModeEnter([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + //! Notifies subscribers of the a given viewport to the activation of the specified editor mode. + virtual void OnEditorModeActivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } - //! Notifies subscribers of the a given viewport to the exiting of the specified editor mode. - virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + //! Notifies subscribers of the a given viewport to the deactivation of the specified editor mode. + virtual void OnEditorModeDeactivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 36c1b09be7..26f724b0aa 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -13,7 +13,7 @@ namespace AzToolsFramework { static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; - AZ::Outcome ViewportEditorModes::SetModeActive(ViewportEditorMode mode) + AZ::Outcome ViewportEditorModes::ActivateMode(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) @@ -28,7 +28,7 @@ namespace AzToolsFramework } } - AZ::Outcome ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) + AZ::Outcome ViewportEditorModes::DeactivateMode(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) { @@ -63,29 +63,29 @@ namespace AzToolsFramework } } - AZ::Outcome ViewportEditorModeTracker::RegisterMode( + AZ::Outcome ViewportEditorModeTracker::ActivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { auto& editorModes = m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; if (editorModes.IsModeActive(mode)) { return AZ::Failure(AZStd::string::format( - "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); + "Duplicate call to ActivateMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); } - if (const auto result = editorModes.SetModeActive(mode); + if (const auto result = editorModes.ActivateMode(mode); !result.IsSuccess()) { return result; } ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModes, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeActivate, editorModes, mode); return AZ::Success(); } - AZ::Outcome ViewportEditorModeTracker::UnregisterMode( + AZ::Outcome ViewportEditorModeTracker::DeactivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { ViewportEditorModes* editorModes = nullptr; @@ -96,7 +96,7 @@ namespace AzToolsFramework if (!editorModes->IsModeActive(mode)) { return AZ::Failure(AZStd::string::format( - "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); + "Duplicate call to DeactivateMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); } } else @@ -105,14 +105,14 @@ namespace AzToolsFramework editorModes = &m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; } - if(const auto result = editorModes->SetModeInactive(mode); + if(const auto result = editorModes->DeactivateMode(mode); !result.IsSuccess()) { return result; } ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModes, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeDeactivate, *editorModes, mode); if (modeWasActive) { @@ -121,7 +121,7 @@ namespace AzToolsFramework else { return AZ::Failure(AZStd::string::format( - "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(mode), + "Call to DeactivateMode for mode '%u' on id '%i' without precursor call to ActivateMode", static_cast(mode), viewportEditorModeInfo.m_id)); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index d67ea5d725..6ae68b39b2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -21,15 +21,14 @@ namespace AzToolsFramework : public ViewportEditorModesInterface { public: - //! The number of currently supported viewport editor modes. static constexpr AZ::u8 NumEditorModes = 4; //! Sets the specified mode as active. - AZ::Outcome SetModeActive(ViewportEditorMode mode); + AZ::Outcome ActivateMode(ViewportEditorMode mode); // Sets the specified mode as inactive. - AZ::Outcome SetModeInactive(ViewportEditorMode mode); + AZ::Outcome DeactivateMode(ViewportEditorMode mode); // ViewportEditorModesInterface ... bool IsModeActive(ViewportEditorMode mode) const override; @@ -49,8 +48,8 @@ namespace AzToolsFramework void UnregisterInterface(); // ViewportEditorModeTrackerInterface overrides ... - AZ::Outcome RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - AZ::Outcome UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + AZ::Outcome ActivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + AZ::Outcome DeactivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetTrackedViewportCount() const override; bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 6103482f05..b3acd91bfe 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -19,15 +19,15 @@ namespace UnitTest using ViewportId = ViewportEditorModeInfo::IdType; using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; - void SetModeActiveAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) + void ActivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) { - const auto result = editorModeState.SetModeActive(mode); + const auto result = editorModeState.ActivateMode(mode); EXPECT_TRUE(result.IsSuccess()); } - void SetModeInactiveAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) + void DeactivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) { - const auto result = editorModeState.SetModeInactive(mode); + const auto result = editorModeState.DeactivateMode(mode); EXPECT_TRUE(result.IsSuccess()); } @@ -35,7 +35,7 @@ namespace UnitTest { for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { - SetModeActiveAndExpectSuccess(editorModeState, static_cast(mode)); + ActivateModeAndExpectSuccess(editorModeState, static_cast(mode)); } } @@ -43,7 +43,7 @@ namespace UnitTest { for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { - SetModeInactiveAndExpectSuccess(editorModeState, static_cast(mode)); + DeactivateModeAndExpectSuccess(editorModeState, static_cast(mode)); } } @@ -111,12 +111,12 @@ namespace UnitTest return m_editorModes; } - void OnEditorModeEnter([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + void OnEditorModeActivate([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onEnter = true; } - virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + virtual void OnEditorModeDeactivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onExit = true; } @@ -167,7 +167,7 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { - SetModeActiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); + ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { @@ -186,7 +186,7 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { SetAllModesActive(m_editorModes); - SetModeInactiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); + DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { @@ -209,7 +209,7 @@ namespace UnitTest // Given only the selected mode active SetAllModesInactive(m_editorModes); { - SetModeActiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); + ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); } const auto editorMode = static_cast(mode); @@ -219,7 +219,7 @@ namespace UnitTest } // When other modes are activated - SetModeActiveAndExpectSuccess(m_editorModes, editorMode); + ActivateModeAndExpectSuccess(m_editorModes, editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -244,7 +244,7 @@ namespace UnitTest { // Given only the selected mode inactive SetAllModesActive(m_editorModes); - SetModeInactiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); + DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -253,7 +253,7 @@ namespace UnitTest } // When other modes are deactivated - SetModeInactiveAndExpectSuccess(m_editorModes, editorMode); + DeactivateModeAndExpectSuccess(m_editorModes, editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -283,13 +283,13 @@ namespace UnitTest TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveReturnsError) { - const auto result = m_editorModes.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); + const auto result = m_editorModes.ActivateMode(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_FALSE(result.IsSuccess()); } TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveReturnsError) { - const auto result = m_editorModes.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); + const auto result = m_editorModes.DeactivateMode(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_FALSE(result.IsSuccess()); } @@ -307,7 +307,7 @@ namespace UnitTest // When a mode is activated for that viewport const auto editorMode = ViewportEditorMode::Default; - m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode); const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); // Expect that viewport to now be tracked @@ -328,8 +328,8 @@ namespace UnitTest // When a mode is deactivated for that viewport const auto editorMode = ViewportEditorMode::Default; const auto expectedErrorMsg = AZStd::string::format( - "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(editorMode), viewportid); - const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + "Call to DeactivateMode for mode '%u' on id '%i' without precursor call to ActivateMode", static_cast(editorMode), viewportid); + const auto result = m_viewportEditorModeTracker.DeactivateMode({ viewportid }, editorMode); // Expect an error due to no precursor activation of that mode EXPECT_FALSE(result.IsSuccess()); @@ -361,7 +361,7 @@ namespace UnitTest const auto editorMode = ViewportEditorMode::Default; { // When the mode is activated for the viewport - const auto result = m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode); // Expect no error as there is no duplicate activation EXPECT_TRUE(result.IsSuccess()); @@ -374,11 +374,11 @@ namespace UnitTest } { // When the mode is activated again for the viewport - const auto result = m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode); // Expect an error for the duplicate activation const auto expectedErrorMsg = AZStd::string::format( - "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + "Duplicate call to ActivateMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); EXPECT_FALSE(result.IsSuccess()); EXPECT_EQ(result.GetError(), expectedErrorMsg); @@ -400,8 +400,8 @@ namespace UnitTest const auto editorMode = ViewportEditorMode::Default; { // When the mode is activated and then deactivated for the viewport - m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); - const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.DeactivateMode({ viewportid }, editorMode); // Expect no error as there is no duplicate deactivation EXPECT_TRUE(result.IsSuccess()); @@ -414,11 +414,11 @@ namespace UnitTest } { // When the mode is deactivated again for the viewport - const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.DeactivateMode({ viewportid }, editorMode); // Expect an error for the duplicate deactivation const auto expectedErrorMsg = AZStd::string::format( - "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + "Duplicate call to DeactivateMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); EXPECT_FALSE(result.IsSuccess()); EXPECT_EQ(result.GetError(), expectedErrorMsg); @@ -446,7 +446,7 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.RegisterMode({ mode }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -478,8 +478,8 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.RegisterMode({ mode }, editorMode); - m_viewportEditorModeTracker.UnregisterMode({ mode }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ mode }, editorMode); + m_viewportEditorModeTracker.DeactivateMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) From 5a25511432fe3c9ad4272034c378356d6d3a651e Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Sep 2021 13:06:01 +0100 Subject: [PATCH 030/115] Change tense of notification bus methods. Signed-off-by: John --- .../API/ViewportEditorModeTrackerNotificationBus.h | 4 ++-- .../ViewportSelection/ViewportEditorModeTracker.cpp | 4 ++-- .../Tests/Viewport/ViewportEditorModeTests.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index d4e5dd4fbb..42a1cb0113 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -53,12 +53,12 @@ namespace AzToolsFramework ////////////////////////////////////////////////////////////////////////// //! Notifies subscribers of the a given viewport to the activation of the specified editor mode. - virtual void OnEditorModeActivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeActivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } //! Notifies subscribers of the a given viewport to the deactivation of the specified editor mode. - virtual void OnEditorModeDeactivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 26f724b0aa..05d21fbf41 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -80,7 +80,7 @@ namespace AzToolsFramework } ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeActivate, editorModes, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeActivated, editorModes, mode); return AZ::Success(); } @@ -112,7 +112,7 @@ namespace AzToolsFramework } ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeDeactivate, *editorModes, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeDeactivated, *editorModes, mode); if (modeWasActive) { diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index b3acd91bfe..527f77b9b0 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -111,12 +111,12 @@ namespace UnitTest return m_editorModes; } - void OnEditorModeActivate([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + void OnEditorModeActivated([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onEnter = true; } - virtual void OnEditorModeDeactivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onExit = true; } From 1dc38518afb4d60f6a472aaa93515be1baef310b Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Sep 2021 14:48:39 +0100 Subject: [PATCH 031/115] Fix malformed string format. Signed-off-by: John --- .../ViewportSelection/ViewportEditorModeTracker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 05d21fbf41..fc16bf3384 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -24,7 +24,7 @@ namespace AzToolsFramework else { return AZ::Failure( - AZStd::string::format(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex)); + AZStd::string::format(ViewportEditorModeLogWindow, "Cannot activate mode %u, mode is not recognized", modeIndex)); } } @@ -38,7 +38,7 @@ namespace AzToolsFramework else { return AZ::Failure( - AZStd::string::format(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex)); + AZStd::string::format(ViewportEditorModeLogWindow, "Cannot deactivate mode %u, mode is not recognized", modeIndex)); } } From 7f3872f41b3c0f903dfe270419c88a0c6e5ac7cb Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Sep 2021 15:27:34 +0100 Subject: [PATCH 032/115] Fix malformed string format (again). Signed-off-by: John --- .../ViewportSelection/ViewportEditorModeTracker.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index fc16bf3384..4adddb02e1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -11,8 +11,6 @@ namespace AzToolsFramework { - static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; - AZ::Outcome ViewportEditorModes::ActivateMode(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); @@ -24,7 +22,7 @@ namespace AzToolsFramework else { return AZ::Failure( - AZStd::string::format(ViewportEditorModeLogWindow, "Cannot activate mode %u, mode is not recognized", modeIndex)); + AZStd::string::format("Cannot activate mode %u, mode is not recognized", modeIndex)); } } @@ -38,7 +36,7 @@ namespace AzToolsFramework else { return AZ::Failure( - AZStd::string::format(ViewportEditorModeLogWindow, "Cannot deactivate mode %u, mode is not recognized", modeIndex)); + AZStd::string::format("Cannot deactivate mode %u, mode is not recognized", modeIndex)); } } From 5a36a375a6f0ab0183662dff0769483f401ccea8 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Sep 2021 15:44:18 +0100 Subject: [PATCH 033/115] Fix Linux warning. Signed-off-by: John --- .../Tests/Viewport/ViewportEditorModeTests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 527f77b9b0..3954ef6dc6 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -446,7 +446,7 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.ActivateMode({ mode }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ viewportId }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -478,8 +478,8 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.ActivateMode({ mode }, editorMode); - m_viewportEditorModeTracker.DeactivateMode({ mode }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ viewportId }, editorMode); + m_viewportEditorModeTracker.DeactivateMode({ viewportId }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) From bcfe3d38786abd850fd5f88f3d967de7e282be11 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Tue, 21 Sep 2021 16:44:19 -0700 Subject: [PATCH 034/115] Revert "Refresh rate driven rendering tick logic (#3375)" This reverts commit db63dcbcd9c6b1758870ed20f91e869394e06ae8. Signed-off-by: nvsickle --- Code/Editor/Core/QtEditorApplication.cpp | 2 +- .../TrackView/SequenceBatchRenderDialog.cpp | 10 - .../AzCore/Component/ComponentApplication.cpp | 19 -- .../AzCore/AzCore/Component/TickBus.h | 2 - .../Atom/Bootstrap/BootstrapNotificationBus.h | 3 +- .../Atom/Bootstrap/BootstrapRequestBus.h | 2 - .../Code/Source/BootstrapSystemComponent.cpp | 39 ++- .../Code/Source/BootstrapSystemComponent.h | 2 - .../Include/Atom/RPI.Public/RenderPipeline.h | 43 +--- .../Code/Include/Atom/RPI.Public/SceneBus.h | 3 - .../Include/Atom/RPI.Public/ViewportContext.h | 49 +--- .../Atom/RPI.Public/ViewportContextBus.h | 8 +- .../Source/RPI.Private/RPISystemComponent.cpp | 18 +- .../Source/RPI.Private/RPISystemComponent.h | 7 +- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 7 +- .../Code/Source/RPI.Public/RenderPipeline.cpp | 44 +--- .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 21 +- Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp | 5 +- .../Source/RPI.Public/ViewportContext.cpp | 144 ++--------- .../Viewport/RenderViewportWidget.h | 24 -- .../RenderViewportWidgetNotificationBus.h | 35 --- .../Source/Viewport/RenderViewportWidget.cpp | 227 ++++-------------- .../Code/atomtoolsframework_files.cmake | 1 - ...AtomViewportDisplayInfoSystemComponent.cpp | 31 +-- .../AtomViewportDisplayInfoSystemComponent.h | 15 +- 25 files changed, 126 insertions(+), 635 deletions(-) delete mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h diff --git a/Code/Editor/Core/QtEditorApplication.cpp b/Code/Editor/Core/QtEditorApplication.cpp index 66ed42af8f..a4aab24be4 100644 --- a/Code/Editor/Core/QtEditorApplication.cpp +++ b/Code/Editor/Core/QtEditorApplication.cpp @@ -44,7 +44,7 @@ enum { // in milliseconds GameModeIdleFrequency = 0, - EditorModeIdleFrequency = 0, + EditorModeIdleFrequency = 1, InactiveModeFrequency = 10, UninitializedFrequency = 9999, }; diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp index 6b3f1c2633..b510315995 100644 --- a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp +++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp @@ -36,9 +36,6 @@ #include "CryEdit.h" #include "Viewport.h" -// Atom Renderer -#include - AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING #include AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING @@ -1237,13 +1234,6 @@ void CSequenceBatchRenderDialog::OnKickIdleTimout() { componentApplication->TickSystem(); } - - // Directly tick the renderer, as it's no longer part of the system tick - if (auto rpiSystem = AZ::RPI::RPISystemInterface::Get()) - { - rpiSystem->SimulationTick(); - rpiSystem->RenderTick(); - } } } diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index a13f11c007..168807cd97 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -74,8 +74,6 @@ #include #include -AZ_CVAR(float, g_simulation_tick_rate, 0, nullptr, AZ::ConsoleFunctorFlags::Null, "The rate at which the game simulation tick loop runs, or 0 for as fast as possible"); - static void PrintEntityName(const AZ::ConsoleCommandContainer& arguments) { if (arguments.empty()) @@ -1396,23 +1394,6 @@ namespace AZ AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick"); EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now)); } - - // If tick rate limiting is on, ensure (1 / g_simulation_tick_rate) ms has elapsed since the last frame, - // sleeping if there's still time remaining. - if (g_simulation_tick_rate > 0.f) - { - now = AZStd::chrono::system_clock::now(); - - // Work in microsecond durations here as that's the native measurement time for time_point - constexpr float microsecondsPerSecond = 1000.f * 1000.f; - const AZStd::chrono::microseconds timeBudgetPerTick(static_cast(microsecondsPerSecond / g_simulation_tick_rate)); - AZStd::chrono::microseconds timeUntilNextTick = m_currentTime + timeBudgetPerTick - now; - - if (timeUntilNextTick.count() > 0) - { - AZStd::this_thread::sleep_for(timeUntilNextTick); - } - } } } diff --git a/Code/Framework/AzCore/AzCore/Component/TickBus.h b/Code/Framework/AzCore/AzCore/Component/TickBus.h index 966a3c303e..e65efb93f2 100644 --- a/Code/Framework/AzCore/AzCore/Component/TickBus.h +++ b/Code/Framework/AzCore/AzCore/Component/TickBus.h @@ -46,8 +46,6 @@ namespace AZ TICK_PRE_RENDER = 750, ///< Suggested tick handler position to update render-related data. - TICK_RENDER = 800, ///< Suggested tick handler position for rendering. - TICK_DEFAULT = 1000, ///< Default tick handler position when the handler is constructed. TICK_UI = 2000, ///< Suggested tick handler position for UI components. diff --git a/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapNotificationBus.h b/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapNotificationBus.h index f4ce51fc02..e40bf39923 100644 --- a/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapNotificationBus.h +++ b/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapNotificationBus.h @@ -56,8 +56,7 @@ namespace AZ ////////////////////////////////////////////////////////////////////////// - virtual void OnBootstrapSceneReady([[maybe_unused]]AZ::RPI::Scene* bootstrapScene){} - virtual void OnFrameRateLimitChanged([[maybe_unused]]float fpsLimit){} + virtual void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) = 0; }; using NotificationBus = AZ::EBus; } // namespace Bootstrap diff --git a/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapRequestBus.h b/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapRequestBus.h index fbf3bad935..21cc91420b 100644 --- a/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapRequestBus.h +++ b/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapRequestBus.h @@ -23,8 +23,6 @@ namespace AZ::Render::Bootstrap virtual AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) = 0; virtual bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) = 0; - virtual float GetFrameRateLimit() const = 0; - virtual void SetFrameRateLimit(float fpsLimit) = 0; protected: ~Request() = default; diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp index e3749175bc..17a8964a8d 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp @@ -42,14 +42,7 @@ #include #include -static void OnFrameRateLimitChanged(const float& fpsLimit) -{ - AZ::Render::Bootstrap::RequestBus::Broadcast( - &AZ::Render::Bootstrap::RequestBus::Events::SetFrameRateLimit, fpsLimit); -} - AZ_CVAR(AZ::CVarFixedString, r_default_pipeline_name, AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default Render pipeline name"); -AZ_CVAR(float, r_fps_limit, 0, OnFrameRateLimitChanged, AZ::ConsoleFunctorFlags::Null, "The maximum framerate to render at, or 0 for unlimited"); namespace AZ { @@ -355,22 +348,6 @@ namespace AZ return true; } - float BootstrapSystemComponent::GetFrameRateLimit() const - { - return r_fps_limit; - } - - void BootstrapSystemComponent::SetFrameRateLimit(float fpsLimit) - { - r_fps_limit = fpsLimit; - if (m_viewportContext) - { - m_viewportContext->SetFpsLimit(r_fps_limit); - } - Render::Bootstrap::NotificationBus::Broadcast( - &Render::Bootstrap::NotificationBus::Events::OnFrameRateLimitChanged, fpsLimit); - } - void BootstrapSystemComponent::CreateDefaultRenderPipeline() { EnsureDefaultRenderPipelineInstalledForScene(m_defaultScene, m_viewportContext); @@ -410,11 +387,23 @@ namespace AZ } void BootstrapSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) - { } + { + // Temp: When running in the launcher without the legacy renderer + // we need to call RenderTick on the viewport context each frame. + if (m_viewportContext) + { + AZ::ApplicationTypeQuery appType; + ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType); + if (appType.IsGame()) + { + m_viewportContext->RenderTick(); + } + } + } int BootstrapSystemComponent::GetTickOrder() { - return TICK_PRE_RENDER; + return TICK_LAST; } void BootstrapSystemComponent::OnWindowClosed() diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h index 438c6cb236..566d19b1a4 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h @@ -69,8 +69,6 @@ namespace AZ // Render::Bootstrap::RequestBus::Handler overrides ... AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) override; bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) override; - float GetFrameRateLimit() const override; - void SetFrameRateLimit(float fpsLimit) override; protected: // Component overrides ... diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h index cc25aa17c4..90389687de 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h @@ -161,25 +161,19 @@ namespace AZ //! Add this RenderPipeline to RPI system's RenderTick and it will be rendered whenever //! the RPI system's RenderTick is called. - //! The RenderPipeline is rendered per RenderTick by default. + //! The RenderPipeline is rendered per RenderTick by default unless AddToRenderTickOnce() was called. void AddToRenderTick(); - //! Add this RenderPipeline to RPI system's RenderTick and it will be rendered every RenderTick - //! after the specified interval has elapsed since the last rendered frame. - //! @param renderInterval The desired time between rendered frames, in seconds. - void AddToRenderTickAtInterval(AZStd::chrono::duration renderInterval); - //! Disable render for this RenderPipeline void RemoveFromRenderTick(); ~RenderPipeline(); - + enum class RenderMode : uint8_t { - RenderEveryTick, //!< Render at each RPI system render tick. - RenderAtTargetRate, //!< Render on RPI system render tick after a target refresh rate interval has passed. - RenderOnce, //!< Render once in next RPI system render tick. - NoRender //!< Render disabled. + RenderEveryTick, // Render at each RPI system render tick + RenderOnce, // Render once in next RPI system render tick + NoRender // Render disabled. }; //! Get current render mode @@ -191,12 +185,6 @@ namespace AZ //! Get draw filter mask RHI::DrawFilterMask GetDrawFilterMask() const; - using FrameNotificationEvent = AZ::Event<>; - //! Notifies a listener when a frame is about to be prepared for render, before SRGs are bound. - void ConnectPrepareFrameHandler(FrameNotificationEvent::Handler& handler); - //! Notifies a listener when the rendering of a frame has finished - void ConnectEndFrameHandler(FrameNotificationEvent::Handler& handler); - private: RenderPipeline() = default; @@ -214,11 +202,8 @@ namespace AZ void OnAddedToScene(Scene* scene); void OnRemovedFromScene(Scene* scene); - // Called before this pipeline is about to be rendered and before SRGs are bound. - void OnPrepareFrame(); - // Called when this pipeline is about to be rendered - void OnStartFrame(); + void OnStartFrame(const TickTimeInfo& tick); // Called when the rendering of current frame is finished. void OnFrameEnd(); @@ -243,14 +228,8 @@ namespace AZ PipelineViewMap m_pipelineViewsByTag; - // The system time when the last time this pipeline render was started - AZStd::chrono::system_clock::time_point m_lastRenderStartTime; - - // The current system time, as of OnPrepareFrame's execution. - AZStd::chrono::system_clock::time_point m_lastRenderRequestTime; - - // The target time between renders when m_renderMode is RenderMode::RenderAtTargetRate - AZStd::chrono::duration m_targetRefreshRate; + /// The system time when the last time this pipeline render was started + float m_lastRenderStartTime = 0; // RenderPipeline's name id, it will be used to identify the render pipeline when it's added to a Scene RenderPipelineId m_nameId; @@ -280,11 +259,7 @@ namespace AZ RHI::DrawFilterTag m_drawFilterTag; // A mask to filter draw items submitted by passes of this render pipeline. // This mask is created from the value of m_drawFilterTag. - RHI::DrawFilterMask m_drawFilterMask = 0; - - // Events for notification on render state - FrameNotificationEvent m_prepareFrameEvent; - FrameNotificationEvent m_endFrameEvent; + RHI::DrawFilterMask m_drawFilterMask = 0; }; } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/SceneBus.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/SceneBus.h index 748c470edf..ca531d2de6 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/SceneBus.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/SceneBus.h @@ -67,9 +67,6 @@ namespace AZ //! Notifies when the PrepareRender phase is ending virtual void OnEndPrepareRender() {} - - //! Notifies when the render tick for a given frame has finished. - virtual void OnFrameEnd() {} }; using SceneNotificationBus = AZ::EBus; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h index feed24a80d..966e6b3016 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h @@ -51,21 +51,9 @@ namespace AZ //! Sets the root scene associated with this viewport. //! This does not provide a default render pipeline, one must be provided to enable rendering. void SetRenderScene(ScenePtr scene); - - //! Gets the maximum frame rate this viewport context's pipeline can render at, 0 for unlimited. - //! The target framerate for the pipeline will be determined by this frame limit and the - //! vsync settings for the current window. - float GetFpsLimit() const; - - //! Sets the maximum frame rate this viewport context's pipeline can render at, 0 for unlimited. - //! The target framerate for the pipeline will be determined by this frame limit and the - //! vsync settings for the current window. - void SetFpsLimit(float fpsLimit); - - //! Gets the target frame rate for this viewport context. - //! This returns the lowest of either the current VSync refresh rate - //! or 0 for an unlimited frame rate (if there's no FPS limit and vsync is off). - float GetTargetFrameRate() const; + //! Runs one simulation and render tick and renders a frame to this viewport's window. + //! @note This is likely to be replaced by a tick management system in the RPI. + void RenderTick(); //! Gets the current name of this ViewportContext. //! This name is used to tie this ViewportContext to its View stack, and ViewportContexts may be @@ -86,28 +74,19 @@ namespace AZ //! \see AzFramework::WindowRequests::GetDpiScaleFactor float GetDpiScalingFactor() const; - //! Gets the current vsync interval, as a divisor of the current refresh rate. - //! A value of 0 indicates that vsync is disabled. - uint32_t GetVsyncInterval() const; - - //! Gets the current display refresh rate, in frames per second. - uint32_t GetRefreshRate() const; - // SceneNotificationBus interface overrides... //! Ensures our default view remains set when our scene's render pipelines are modified. void OnRenderPipelineAdded(RenderPipelinePtr pipeline) override; //! Ensures our default view remains set when our scene's render pipelines are modified. void OnRenderPipelineRemoved(RenderPipeline* pipeline) override; + //! OnBeginPrepareRender is forwarded to our RenderTick notification to allow subscribers to do rendering. + void OnBeginPrepareRender() override; // WindowNotificationBus interface overrides... //! Used to fire a notification when our window resizes. void OnWindowResized(uint32_t width, uint32_t height) override; //! Used to fire a notification when our window DPI changes. void OnDpiScaleFactorChanged(float dpiScaleFactor) override; - //! Used to fire a notification when our vsync interval changes. - void OnVsyncIntervalChanged(uint32_t interval) override; - //! Used to fire a notification when our refresh rate changes. - void OnRefreshRateChanged(uint32_t refreshRate) override; using SizeChangedEvent = AZ::Event; //! Notifies consumers when the viewport size has changed. @@ -119,12 +98,6 @@ namespace AZ //! Alternatively, connect to ViewportContextNotificationsBus and listen to ViewportContextNotifications::OnViewportDpiScalingChanged. void ConnectDpiScalingFactorChangedHandler(ScalarChangedEvent::Handler& handler); - using UintChangedEvent = AZ::Event; - //! Notifies consumers when the vsync interval has changed. - void ConnectVsyncIntervalChangedHandler(UintChangedEvent::Handler& handler); - //! Notifies consumers when the refresh rate has changed. - void ConnectRefreshRateChangedHandler(UintChangedEvent::Handler& handler); - using MatrixChangedEvent = AZ::Event; //! Notifies consumers when the view matrix has changed. void ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler); @@ -166,24 +139,15 @@ namespace AZ void SetDefaultView(ViewPtr view); // Ensures our render pipeline's default camera matches ours. void UpdatePipelineView(); - // Ensures our render pipeline refresh rate matches our refresh rate. - void UpdatePipelineRefreshRate(); - // Resets the current pipeline reference and ensures pipeline events are disconnected. - void ResetCurrentPipeline(); ScenePtr m_rootScene; WindowContextSharedPtr m_windowContext; ViewPtr m_defaultView; AzFramework::WindowSize m_viewportSize; float m_viewportDpiScaleFactor = 1.0f; - uint32_t m_vsyncInterval = 1; - uint32_t m_refreshRate = 60; - float m_fpsLimit = 0.f; SizeChangedEvent m_sizeChangedEvent; ScalarChangedEvent m_dpiScalingFactorChangedEvent; - UintChangedEvent m_vsyncIntervalChangedEvent; - UintChangedEvent m_refreshRateChangedEvent; MatrixChangedEvent m_viewMatrixChangedEvent; MatrixChangedEvent::Handler m_onViewMatrixChangedHandler; MatrixChangedEvent m_projectionMatrixChangedEvent; @@ -193,9 +157,6 @@ namespace AZ ViewChangedEvent m_defaultViewChangedEvent; ViewportIdEvent m_aboutToBeDestroyedEvent; - AZ::Event<>::Handler m_prepareFrameHandler; - AZ::Event<>::Handler m_endFrameHandler; - ViewportContextManager* m_manager; RenderPipelinePtr m_currentPipeline; Name m_name; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h index fa13a3987a..0b53172ba2 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h @@ -110,13 +110,11 @@ namespace AZ virtual void OnViewportSizeChanged(AzFramework::WindowSize size){AZ_UNUSED(size);} //! Called when the window DPI scaling changes for a given viewport context. virtual void OnViewportDpiScalingChanged(float dpiScale){AZ_UNUSED(dpiScale);} - //! Called when the active view changes for a given viewport context. + //! Called when the active view for a given viewport context name changes. virtual void OnViewportDefaultViewChanged(AZ::RPI::ViewPtr view){AZ_UNUSED(view);} //! Called when the viewport is to be rendered. - //! Add draws to this function if they only need to be rendered to this viewport. - virtual void OnRenderTick(){} - //! Called when the viewport finishes rendering a frame. - virtual void OnFrameEnd(){} + //! Add draws to this functions if they only need to be rendered to this viewport. + virtual void OnRenderTick(){}; protected: ~ViewportContextNotifications() = default; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp index 789d43712e..2567d221e5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp @@ -14,9 +14,6 @@ #include #include -#include -#include -#include #include #include @@ -96,29 +93,20 @@ namespace AZ } m_rpiSystem.Initialize(m_rpiDescriptor); - AZ::TickBus::Handler::BusConnect(); + AZ::SystemTickBus::Handler::BusConnect(); } void RPISystemComponent::Deactivate() { - AZ::TickBus::Handler::BusDisconnect(); + AZ::SystemTickBus::Handler::BusDisconnect(); m_rpiSystem.Shutdown(); } - void RPISystemComponent::OnTick([[maybe_unused]]float deltaTime, [[maybe_unused]]ScriptTimePoint time) + void RPISystemComponent::OnSystemTick() { - if (deltaTime == 0.f) - { - return; - } - m_rpiSystem.SimulationTick(); m_rpiSystem.RenderTick(); } - int RPISystemComponent::GetTickOrder() - { - return AZ::ComponentTickBus::TICK_RENDER; - } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.h b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.h index 7933e1581c..e0a128c3f1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.h +++ b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.h @@ -32,7 +32,7 @@ namespace AZ */ class RPISystemComponent final : public AZ::Component - , private AZ::TickBus::Handler + , public AZ::SystemTickBus::Handler { public: AZ_COMPONENT(RPISystemComponent, "{83E301F3-7A0C-4099-B530-9342B91B1BC0}"); @@ -50,9 +50,8 @@ namespace AZ private: RPISystemComponent(const RPISystemComponent&) = delete; - // TickBus overrides... - void OnTick(float deltaTime, ScriptTimePoint time) override; - int GetTickOrder() override; + // SystemTickBus overrides... + void OnSystemTick() override; RPISystem m_rpiSystem; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index c5e871697b..a8d94e9a91 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -93,11 +93,8 @@ namespace AZ void Pass::SetEnabled(bool enabled) { - if (m_flags.m_enabled != enabled) - { - m_flags.m_enabled = enabled; - OnHierarchyChange(); - } + m_flags.m_enabled = enabled; + OnHierarchyChange(); } bool Pass::IsEnabled() const diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 409a084e4f..1b99abae4e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -301,26 +301,6 @@ namespace AZ m_drawFilterMask = 0; } - void RenderPipeline::OnPrepareFrame() - { - m_lastRenderRequestTime = AZStd::chrono::system_clock::now(); - - // If we're attempting to render at a target interval, check to see if we're within - // 1ms of that interval, enabling rendering only if we are. - if (m_renderMode == RenderMode::RenderAtTargetRate) - { - constexpr AZStd::chrono::duration updateThresholdMs(0.001f); - const bool shouldRender = - m_lastRenderRequestTime - m_lastRenderStartTime + updateThresholdMs >= m_targetRefreshRate; - m_rootPass->SetEnabled(shouldRender); - } - - if (NeedsRender()) - { - m_prepareFrameEvent.Signal(); - } - } - void RenderPipeline::OnPassModified() { if (m_needsPassRecreate) @@ -395,11 +375,11 @@ namespace AZ m_scene->RemoveRenderPipeline(m_nameId); } - void RenderPipeline::OnStartFrame() + void RenderPipeline::OnStartFrame(const TickTimeInfo& tick) { AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame"); - m_lastRenderStartTime = m_lastRenderRequestTime; + m_lastRenderStartTime = tick.m_currentGameTime; OnPassModified(); @@ -427,7 +407,6 @@ namespace AZ { RemoveFromRenderTick(); } - m_endFrameEvent.Signal(); } void RenderPipeline::CollectPersistentViews(AZStd::map& outViewMasks) const @@ -510,13 +489,6 @@ namespace AZ m_renderMode = RenderMode::RenderEveryTick; } - void RenderPipeline::AddToRenderTickAtInterval(AZStd::chrono::duration renderInterval) - { - m_rootPass->SetEnabled(false); - m_renderMode = RenderMode::RenderAtTargetRate; - m_targetRefreshRate = renderInterval; - } - void RenderPipeline::RemoveFromRenderTick() { m_renderMode = RenderMode::NoRender; @@ -530,7 +502,7 @@ namespace AZ bool RenderPipeline::NeedsRender() const { - return m_rootPass->IsEnabled(); + return m_renderMode != RenderMode::NoRender; } RHI::DrawFilterTag RenderPipeline::GetDrawFilterTag() const @@ -543,16 +515,6 @@ namespace AZ return m_drawFilterMask; } - void RenderPipeline::ConnectPrepareFrameHandler(FrameNotificationEvent::Handler& handler) - { - handler.Connect(m_prepareFrameEvent); - } - - void RenderPipeline::ConnectEndFrameHandler(FrameNotificationEvent::Handler& handler) - { - handler.Connect(m_endFrameEvent); - } - void RenderPipeline::SetDrawFilterTag(RHI::DrawFilterTag tag) { m_drawFilterTag = tag; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 778548f14c..08370c44d6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -420,7 +420,7 @@ namespace AZ } } - void Scene::PrepareRender([[maybe_unused]]const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) + void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) { AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender"); @@ -431,27 +431,20 @@ namespace AZ SceneNotificationBus::Event(GetId(), &SceneNotification::OnBeginPrepareRender); - // Get active pipelines which need to be rendered and notify them of an impending frame. + // Get active pipelines which need to be rendered and notify them frame started AZStd::vector activePipelines; { - AZ_PROFILE_SCOPE(RPI, "Scene: OnPrepareFrame"); + AZ_PROFILE_SCOPE(RPI, "Scene: OnStartFrame"); for (auto& pipeline : m_pipelines) { - pipeline->OnPrepareFrame(); if (pipeline->NeedsRender()) { activePipelines.push_back(pipeline); + pipeline->OnStartFrame(tickInfo); } } } - // Get active pipelines which need to be rendered and notify them frame started - for (const auto& pipeline : activePipelines) - { - AZ_PROFILE_SCOPE(RPI, "Scene: OnStartFrame"); - pipeline->OnStartFrame(); - } - // Return if there is no active render pipeline if (activePipelines.empty()) { @@ -591,12 +584,10 @@ namespace AZ void Scene::OnFrameEnd() { AZ_PROFILE_SCOPE(RPI, "Scene: OnFrameEnd"); - bool didRender = false; for (auto& pipeline : m_pipelines) { if (pipeline->NeedsRender()) { - didRender = true; pipeline->OnFrameEnd(); } } @@ -604,10 +595,6 @@ namespace AZ { fp->OnRenderEnd(); } - if (didRender) - { - SceneNotificationBus::Event(GetId(), &SceneNotification::OnFrameEnd); - } } void Scene::UpdateSrgs() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp index c2356cea45..8c1e38ba58 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp @@ -241,10 +241,7 @@ namespace AZ { AZ_PROFILE_SCOPE(RPI, "View: FinalizeDrawLists"); m_drawListContext.FinalizeLists(); - if (m_passesByDrawList) - { - SortFinalizedDrawLists(); - } + SortFinalizedDrawLists(); } void View::SortFinalizedDrawLists() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp index 3dcbae2fb9..77114e5cf5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp @@ -25,13 +25,14 @@ namespace AZ , m_viewportSize(1, 1) { m_windowContext->Initialize(device, nativeWindow); - AzFramework::WindowRequestBus::Event(nativeWindow, [this](AzFramework::WindowRequestBus::Events* window) - { - m_viewportSize = window->GetClientAreaSize(); - m_viewportDpiScaleFactor = window->GetDpiScaleFactor(); - m_vsyncInterval = window->GetSyncInterval(); - m_refreshRate = window->GetDisplayRefreshRate(); - }); + AzFramework::WindowRequestBus::EventResult( + m_viewportSize, + nativeWindow, + &AzFramework::WindowRequestBus::Events::GetClientAreaSize); + AzFramework::WindowRequestBus::EventResult( + m_viewportDpiScaleFactor, + nativeWindow, + &AzFramework::WindowRequestBus::Events::GetDpiScaleFactor); AzFramework::WindowNotificationBus::Handler::BusConnect(nativeWindow); AzFramework::ViewportRequestBus::Handler::BusConnect(id); @@ -45,20 +46,6 @@ namespace AZ m_viewMatrixChangedEvent.Signal(matrix); }); - m_prepareFrameHandler = RenderPipeline::FrameNotificationEvent::Handler( - [this]() - { - ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick); - ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick); - }); - - m_endFrameHandler = RenderPipeline::FrameNotificationEvent::Handler( - [this]() - { - ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnFrameEnd); - ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnFrameEnd); - }); - SetRenderScene(renderScene); } @@ -124,38 +111,26 @@ namespace AZ { SceneNotificationBus::Handler::BusConnect(m_rootScene->GetId()); } - ResetCurrentPipeline(); + m_currentPipeline.reset(); UpdatePipelineView(); - UpdatePipelineRefreshRate(); } m_sceneChangedEvent.Signal(scene); } - float ViewportContext::GetFpsLimit() const + void ViewportContext::RenderTick() { - return m_fpsLimit; - } - - void ViewportContext::SetFpsLimit(float fpsLimit) - { - m_fpsLimit = fpsLimit; - UpdatePipelineRefreshRate(); - } - - float ViewportContext::GetTargetFrameRate() const - { - float targetFrameRate = GetFpsLimit(); - const AZ::u32 vsyncInterval = GetVsyncInterval(); - if (vsyncInterval != 0) + // add the current pipeline to next render tick if it's not already added. + if (m_currentPipeline && m_currentPipeline->GetRenderMode() != RenderPipeline::RenderMode::RenderOnce) { - const float vsyncFrameRate = static_cast(GetRefreshRate()) / static_cast(vsyncInterval); - if (targetFrameRate == 0.f || vsyncFrameRate < targetFrameRate) - { - targetFrameRate = vsyncFrameRate; - } + m_currentPipeline->AddToRenderTickOnce(); } - return targetFrameRate; + } + + void ViewportContext::OnBeginPrepareRender() + { + ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick); + ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick); } AZ::Name ViewportContext::GetName() const @@ -183,16 +158,6 @@ namespace AZ return m_viewportDpiScaleFactor; } - uint32_t ViewportContext::GetVsyncInterval() const - { - return m_vsyncInterval; - } - - uint32_t ViewportContext::GetRefreshRate() const - { - return m_refreshRate; - } - void ViewportContext::ConnectSizeChangedHandler(SizeChangedEvent::Handler& handler) { handler.Connect(m_sizeChangedEvent); @@ -203,16 +168,6 @@ namespace AZ handler.Connect(m_dpiScalingFactorChangedEvent); } - void ViewportContext::ConnectVsyncIntervalChangedHandler(UintChangedEvent::Handler& handler) - { - handler.Connect(m_vsyncIntervalChangedEvent); - } - - void ViewportContext::ConnectRefreshRateChangedHandler(UintChangedEvent::Handler& handler) - { - handler.Connect(m_refreshRateChangedEvent); - } - void ViewportContext::ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler) { handler.Connect(m_viewMatrixChangedEvent); @@ -308,43 +263,12 @@ namespace AZ m_currentPipelineChangedEvent.Signal(m_currentPipeline); } - if (m_currentPipeline) + if (auto pipeline = GetCurrentPipeline()) { - if (!m_prepareFrameHandler.IsConnected()) - { - m_currentPipeline->ConnectPrepareFrameHandler(m_prepareFrameHandler); - m_currentPipeline->ConnectEndFrameHandler(m_endFrameHandler); - } - m_currentPipeline->SetDefaultView(m_defaultView); + pipeline->SetDefaultView(m_defaultView); } } - void ViewportContext::UpdatePipelineRefreshRate() - { - if (!m_currentPipeline) - { - return; - } - - const float refreshRate = GetTargetFrameRate(); - // If we have a truly unlimited framerate, just render every tick - if (refreshRate == 0.f) - { - m_currentPipeline->AddToRenderTick(); - } - else - { - m_currentPipeline->AddToRenderTickAtInterval(AZStd::chrono::duration(1.f / refreshRate)); - } - } - - void ViewportContext::ResetCurrentPipeline() - { - m_prepareFrameHandler.Disconnect(); - m_endFrameHandler.Disconnect(); - m_currentPipeline.reset(); - } - RenderPipelinePtr ViewportContext::GetCurrentPipeline() { return m_currentPipeline; @@ -357,9 +281,8 @@ namespace AZ // in the event prioritization is added later if (pipeline->GetWindowHandle() == m_windowContext->GetWindowHandle()) { - ResetCurrentPipeline(); + m_currentPipeline.reset(); UpdatePipelineView(); - UpdatePipelineRefreshRate(); } } @@ -367,9 +290,8 @@ namespace AZ { if (m_currentPipeline.get() == pipeline) { - ResetCurrentPipeline(); + m_currentPipeline.reset(); UpdatePipelineView(); - UpdatePipelineRefreshRate(); } } @@ -383,30 +305,10 @@ namespace AZ } } - void ViewportContext::OnRefreshRateChanged(uint32_t refreshRate) - { - if (m_refreshRate != refreshRate) - { - m_refreshRate = refreshRate; - m_refreshRateChangedEvent.Signal(m_refreshRate); - UpdatePipelineRefreshRate(); - } - } - void ViewportContext::OnDpiScaleFactorChanged(float dpiScaleFactor) { m_viewportDpiScaleFactor = dpiScaleFactor; m_dpiScalingFactorChangedEvent.Signal(dpiScaleFactor); } - - void ViewportContext::OnVsyncIntervalChanged(uint32_t interval) - { - if (m_vsyncInterval != interval) - { - m_vsyncInterval = interval; - m_vsyncIntervalChangedEvent.Signal(m_vsyncInterval); - UpdatePipelineRefreshRate(); - } - } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h index 318a49027a..623d759c9f 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -22,8 +21,6 @@ #include #include #include -#include -#include namespace AtomToolsFramework { @@ -38,8 +35,6 @@ namespace AtomToolsFramework , public AzFramework::WindowRequestBus::Handler , protected AzFramework::InputChannelEventListener , protected AZ::TickBus::Handler - , protected AZ::Render::Bootstrap::NotificationBus::Handler - , protected AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler { public: //! Creates a RenderViewportWidget. @@ -126,7 +121,6 @@ namespace AtomToolsFramework // AZ::TickBus::Handler ... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - int GetTickOrder() override; // QWidget ... void resizeEvent(QResizeEvent *event) override; @@ -134,21 +128,9 @@ namespace AtomToolsFramework void enterEvent(QEvent* event) override; void leaveEvent(QEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; - void focusInEvent(QFocusEvent* event) override; - - // AZ::Render::Bootstrap::NotificationBus::Handler ... - void OnFrameRateLimitChanged(float fpsLimit) override; - - // AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler ... - void OnInactiveViewportFrameRateChanged(float fpsLimit) override; private: - AzFramework::NativeWindowHandle GetNativeWindowHandle() const; - void UpdateFrameRate(); - - void SetScreen(QScreen* screen); void SendWindowResizeEvent(); - void NotifyUpdateRefreshRate(); // The underlying ViewportContext, our entry-point to the Atom RPI. AZ::RPI::ViewportContextPtr m_viewportContext; @@ -169,11 +151,5 @@ namespace AtomToolsFramework AZ::ScriptTimePoint m_time; // Maps our internal Qt events into AzFramework InputChannels for our ViewportControllerList. AzToolsFramework::QtEventToAzInputMapper* m_inputChannelMapper = nullptr; - // Stores our current screen, used for tracking the current refresh rate. - QScreen* m_screen = nullptr; - // Stores the last RenderViewportWidget that has received user focus. - // This is used for optional framerate throtting for "inactive" viewports via the - // ed_inactive_viewport_fps_limit CVAR. - AZ::EnvironmentVariable m_lastFocusedViewport; }; } //namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h deleted file mode 100644 index 0563bd6bf2..0000000000 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h +++ /dev/null @@ -1,35 +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 AtomToolsFramework -{ - //! Provides an interface for providing notifications specific to RenderViewportWidget. - //! @note Most behaviors in RenderViewportWidget are handled by its underyling - //! ViewportContext, this bus is specifically for functionality exclusive to the - //! Qt layer provided by RenderViewportWidget. - class RenderViewportWidgetNotifications : public AZ::EBusTraits - { - public: - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; - - //! Triggered when the idle frame rate limit for inactive viewports changed. - //! Controlled by the ed_inactive_viewport_fps_limit CVAR. - //! Active viewports are controlled by the r_fps_limit CVAR. - virtual void OnInactiveViewportFrameRateChanged([[maybe_unused]]float fpsLimit){} - - protected: - ~RenderViewportWidgetNotifications() = default; - }; - - using RenderViewportWidgetNotificationBus = AZ::EBus; -} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index 2a15041e20..7192afebf7 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -6,42 +6,23 @@ * */ -#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 - -static void OnInactiveViewportFrameRateChanged(const float& fpsLimit) -{ - AtomToolsFramework::RenderViewportWidgetNotificationBus::Broadcast( - &AtomToolsFramework::RenderViewportWidgetNotificationBus::Events::OnInactiveViewportFrameRateChanged, fpsLimit); -} - -AZ_CVAR( - float, - ed_inactive_viewport_fps_limit, - 0, - OnInactiveViewportFrameRateChanged, - AZ::ConsoleFunctorFlags::Null, - "The maximum framerate to render viewports that don't have focus at"); - -static constexpr const char* LastFocusedViewportVariableName = "AtomToolsFramework::RenderViewportWidget::LastFocusedViewport"; +#include namespace AtomToolsFramework { @@ -49,12 +30,6 @@ namespace AtomToolsFramework : QWidget(parent) , AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDefault()) { - m_lastFocusedViewport = AZ::Environment::FindVariable(LastFocusedViewportVariableName); - if (!m_lastFocusedViewport) - { - m_lastFocusedViewport = AZ::Environment::CreateVariable(LastFocusedViewportVariableName, nullptr); - } - if (shouldInitializeViewportContext) { InitializeViewportContext(); @@ -63,24 +38,13 @@ namespace AtomToolsFramework setUpdatesEnabled(false); setFocusPolicy(Qt::FocusPolicy::WheelFocus); setMouseTracking(true); - - // Wait a frame for our window handle to be constructed, then wire up our screen change signals. - QTimer::singleShot( - 0, - [this]() - { - QObject::connect(windowHandle(), &QWindow::screenChanged, this, &RenderViewportWidget::SetScreen); - }); - SetScreen(screen()); } bool RenderViewportWidget::InitializeViewportContext(AzFramework::ViewportId id) { if (m_viewportContext != nullptr) { - AZ_Assert( - id == AzFramework::InvalidViewportId || m_viewportContext->GetId() == id, - "Attempted to reinitialize RenderViewportWidget with a different ID"); + AZ_Assert(id == AzFramework::InvalidViewportId || m_viewportContext->GetId() == id, "Attempted to reinitialize RenderViewportWidget with a different ID"); return true; } @@ -95,7 +59,7 @@ namespace AtomToolsFramework // Before we do anything else, we must create a ViewportContext which will give us a ViewportId if we didn't manually specify one. AZ::RPI::ViewportContextRequestsInterface::CreationParameters params; params.device = AZ::RHI::RHISystemInterface::Get()->GetDevice(); - params.windowHandle = GetNativeWindowHandle(); + params.windowHandle = reinterpret_cast(winId()); params.id = id; AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle); m_viewportContext = viewportContextManager->CreateViewportContext(AZ::Name(), params); @@ -116,46 +80,29 @@ namespace AtomToolsFramework AzFramework::InputChannelEventListener::Connect(); AZ::TickBus::Handler::BusConnect(); AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle); - AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect(); - AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler::BusConnect(); m_inputChannelMapper = new AzToolsFramework::QtEventToAzInputMapper(this, id); // Forward input events to our controller list. - QObject::connect( - m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this, + QObject::connect(m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this, [this](const AzFramework::InputChannel* inputChannel, QEvent* event) - { - const AzFramework::NativeWindowHandle windowId = GetNativeWindowHandle(); - if (m_controllerList->HandleInputChannelEvent( - AzFramework::ViewportControllerInputEvent{ GetId(), windowId, *inputChannel })) - { - // If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate. - if (event) - { - event->setAccepted(true); - } - } - }); - - // Update our target frame rate. If we're the only viewport, become active. - if (m_lastFocusedViewport.Get() == nullptr) { - m_lastFocusedViewport.Set(this); - } - UpdateFrameRate(); - + AzFramework::NativeWindowHandle windowId = reinterpret_cast(winId()); + if (m_controllerList->HandleInputChannelEvent(AzFramework::ViewportControllerInputEvent{GetId(), windowId, *inputChannel})) + { + // If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate. + if (event) + { + event->setAccepted(true); + } + } + }); return true; } RenderViewportWidget::~RenderViewportWidget() { - if (m_lastFocusedViewport.Get() == this) - { - m_lastFocusedViewport.Set(nullptr); - } - AzFramework::WindowRequestBus::Handler::BusDisconnect(); AZ::TickBus::Handler::BusDisconnect(); AzFramework::InputChannelEventListener::Disconnect(); @@ -234,22 +181,17 @@ namespace AtomToolsFramework bool shouldConsumeEvent = true; - const bool eventHandled = m_controllerList->HandleInputChannelEvent({ GetId(), GetNativeWindowHandle(), inputChannel }); + AzFramework::NativeWindowHandle windowId = reinterpret_cast(winId()); + const bool eventHandled = m_controllerList->HandleInputChannelEvent({GetId(), windowId, inputChannel}); - // If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might - // need), consume it. + // If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might need), consume it. return eventHandled && shouldConsumeEvent; } - void RenderViewportWidget::OnTick([[maybe_unused]] float deltaTime, AZ::ScriptTimePoint time) + void RenderViewportWidget::OnTick([[maybe_unused]]float deltaTime, AZ::ScriptTimePoint time) { m_time = time; - m_controllerList->UpdateViewport({ GetId(), AzFramework::FloatSeconds(deltaTime), m_time }); - } - - int RenderViewportWidget::GetTickOrder() - { - return AZ::ComponentTickBus::TICK_PRE_RENDER; + m_controllerList->UpdateViewport({GetId(), AzFramework::FloatSeconds(deltaTime), m_time}); } void RenderViewportWidget::resizeEvent([[maybe_unused]] QResizeEvent* event) @@ -277,75 +219,6 @@ namespace AtomToolsFramework m_mousePosition = event->localPos(); } - void RenderViewportWidget::focusInEvent([[maybe_unused]] QFocusEvent* event) - { - RenderViewportWidget* lastFocusedViewport = m_lastFocusedViewport.Get(); - if (lastFocusedViewport == this) - { - return; - } - - RenderViewportWidget* previousFocusWidget = lastFocusedViewport; - m_lastFocusedViewport.Set(this); - - // Ensure this viewport and whatever viewport last had focus (if any) respect - // the active / inactive viewport frame rate settings. - UpdateFrameRate(); - if (previousFocusWidget != nullptr) - { - previousFocusWidget->UpdateFrameRate(); - } - } - - void RenderViewportWidget::OnFrameRateLimitChanged([[maybe_unused]] float fpsLimit) - { - UpdateFrameRate(); - } - - void RenderViewportWidget::OnInactiveViewportFrameRateChanged([[maybe_unused]] float fpsLimit) - { - UpdateFrameRate(); - } - - AzFramework::NativeWindowHandle RenderViewportWidget::GetNativeWindowHandle() const - { - return reinterpret_cast(winId()); - } - - void RenderViewportWidget::UpdateFrameRate() - { - if (ed_inactive_viewport_fps_limit > 0.f && m_lastFocusedViewport.Get() != this) - { - m_viewportContext->SetFpsLimit(ed_inactive_viewport_fps_limit); - } - else - { - float fpsLimit = 0.f; - AZ::Render::Bootstrap::RequestBus::BroadcastResult(fpsLimit, &AZ::Render::Bootstrap::RequestBus::Events::GetFrameRateLimit); - m_viewportContext->SetFpsLimit(fpsLimit); - } - } - - void RenderViewportWidget::SetScreen(QScreen* screen) - { - if (m_screen != screen) - { - if (m_screen) - { - QObject::disconnect(m_screen, &QScreen::refreshRateChanged, this, &RenderViewportWidget::NotifyUpdateRefreshRate); - } - - if (screen) - { - QObject::connect(m_screen, &QScreen::refreshRateChanged, this, &RenderViewportWidget::NotifyUpdateRefreshRate); - } - - NotifyUpdateRefreshRate(); - - m_screen = screen; - } - } - void RenderViewportWidget::SendWindowResizeEvent() { // Scale the size by the DPI of the platform to @@ -353,14 +226,8 @@ namespace AtomToolsFramework const QSize uiWindowSize = size(); const QSize windowSize = uiWindowSize * devicePixelRatioF(); - AzFramework::WindowNotificationBus::Event( - GetNativeWindowHandle(), &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height()); - } - - void RenderViewportWidget::NotifyUpdateRefreshRate() - { - AzFramework::WindowNotificationBus::Event( - GetNativeWindowHandle(), &AzFramework::WindowNotificationBus::Events::OnRefreshRateChanged, GetDisplayRefreshRate()); + const AzFramework::NativeWindowHandle windowId = reinterpret_cast(winId()); + AzFramework::WindowNotificationBus::Event(windowId, &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height()); } AZ::Name RenderViewportWidget::GetCurrentContextName() const @@ -418,7 +285,9 @@ namespace AtomToolsFramework // Build camera state from Atom camera transforms AzFramework::CameraState cameraState = AzFramework::CreateCameraFromWorldFromViewMatrix( - currentView->GetViewToWorldMatrix(), AZ::Vector2{ aznumeric_cast(width()), aznumeric_cast(height()) }); + currentView->GetViewToWorldMatrix(), + AZ::Vector2{aznumeric_cast(width()), aznumeric_cast(height())} + ); AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, currentView->GetViewToClipMatrix()); // Convert from Z-up @@ -430,7 +299,8 @@ namespace AtomToolsFramework AzFramework::ScreenPoint RenderViewportWidget::ViewportWorldToScreen(const AZ::Vector3& worldPosition) { - if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView(); currentView == nullptr) + if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView(); + currentView == nullptr) { return AzFramework::ScreenPoint(0, 0); } @@ -443,10 +313,12 @@ namespace AtomToolsFramework const auto& cameraProjection = m_viewportContext->GetCameraProjectionMatrix(); const auto& cameraView = m_viewportContext->GetCameraViewMatrix(); - const AZ::Vector4 normalizedScreenPosition{ screenPosition.m_x * 2.f / width() - 1.0f, - (height() - screenPosition.m_y) * 2.f / height() - 1.0f, - 1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth - 1.f }; + const AZ::Vector4 normalizedScreenPosition { + screenPosition.m_x * 2.f / width() - 1.0f, + (height() - screenPosition.m_y) * 2.f / height() - 1.0f, + 1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth + 1.f + }; AZ::Matrix4x4 worldFromScreen = cameraProjection * cameraView; worldFromScreen.InvertFull(); @@ -475,7 +347,7 @@ namespace AtomToolsFramework AZ::Vector3 rayDirection = pos1.value() - pos0.value(); rayDirection.Normalize(); - return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{ rayOrigin, rayDirection }; + return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{rayOrigin, rayDirection}; } float RenderViewportWidget::DeviceScalingFactor() @@ -505,12 +377,12 @@ namespace AtomToolsFramework AzFramework::WindowSize RenderViewportWidget::GetClientAreaSize() const { - return AzFramework::WindowSize{ aznumeric_cast(width()), aznumeric_cast(height()) }; + return AzFramework::WindowSize{aznumeric_cast(width()), aznumeric_cast(height())}; } void RenderViewportWidget::ResizeClientArea(AzFramework::WindowSize clientAreaSize) { - const QSize targetSize = QSize{ aznumeric_cast(clientAreaSize.m_width), aznumeric_cast(clientAreaSize.m_height) }; + const QSize targetSize = QSize{aznumeric_cast(clientAreaSize.m_width), aznumeric_cast(clientAreaSize.m_height)}; resize(targetSize); } @@ -520,7 +392,7 @@ namespace AtomToolsFramework return false; } - void RenderViewportWidget::SetFullScreenState([[maybe_unused]] bool fullScreenState) + void RenderViewportWidget::SetFullScreenState([[maybe_unused]]bool fullScreenState) { // The RenderViewportWidget does not currently support full screen. } @@ -543,20 +415,11 @@ namespace AtomToolsFramework uint32_t RenderViewportWidget::GetDisplayRefreshRate() const { - return static_cast(screen()->refreshRate()); + return 60; } uint32_t RenderViewportWidget::GetSyncInterval() const { - uint32_t interval = 1; - - // Get vsync_interval from AzFramework::NativeWindow, which owns it. - // NativeWindow also handles broadcasting OnVsyncIntervalChanged to all - // WindowNotificationBus listeners. - if (auto console = AZ::Interface::Get()) - { - console->GetCvarValue("vsync_interval", interval); - } - return interval; + return 1; } -} // namespace AtomToolsFramework +} //namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index a24b45179f..3d4bb82eec 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -28,7 +28,6 @@ set(FILES Include/AtomToolsFramework/Util/MaterialPropertyUtil.h Include/AtomToolsFramework/Util/Util.h Include/AtomToolsFramework/Viewport/RenderViewportWidget.h - Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h Include/AtomToolsFramework/Window/AtomToolsMainWindow.h diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp index bf356fa4b5..7d659ebb7a 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp @@ -183,15 +183,6 @@ namespace AZ::Render DrawFramerate(); } - void AtomViewportDisplayInfoSystemComponent::OnFrameEnd() - { - auto currentTime = AZStd::chrono::system_clock::now(); - if (!m_fpsHistory.empty()) - { - m_fpsHistory.back().m_endFrameTime = currentTime; - } - } - AtomBridge::ViewportInfoDisplayState AtomViewportDisplayInfoSystemComponent::GetDisplayState() const { return aznumeric_cast(r_displayInfo.operator int()); @@ -257,11 +248,11 @@ namespace AZ::Render void AtomViewportDisplayInfoSystemComponent::UpdateFramerate() { auto currentTime = AZStd::chrono::system_clock::now(); - while (!m_fpsHistory.empty() && (currentTime - m_fpsHistory.front().m_beginFrameTime) > m_fpsInterval) + while (!m_fpsHistory.empty() && (currentTime - m_fpsHistory.front()) > m_fpsInterval) { m_fpsHistory.pop_front(); } - m_fpsHistory.push_back(FrameTimingInfo(currentTime)); + m_fpsHistory.push_back(currentTime); } void AtomViewportDisplayInfoSystemComponent::DrawFramerate() @@ -270,31 +261,25 @@ namespace AZ::Render double minFPS = DBL_MAX; double maxFPS = 0; AZStd::chrono::duration deltaTime; - AZStd::chrono::milliseconds totalFrameMS(0); for (const auto& time : m_fpsHistory) { if (lastTime.has_value()) { - deltaTime = time.m_beginFrameTime - lastTime.value(); + deltaTime = time - lastTime.value(); double fps = AZStd::chrono::seconds(1) / deltaTime; minFPS = AZStd::min(minFPS, fps); maxFPS = AZStd::max(maxFPS, fps); } - lastTime = time.m_beginFrameTime; - - if (time.m_endFrameTime.has_value()) - { - totalFrameMS += time.m_endFrameTime.value() - time.m_beginFrameTime; - } + lastTime = time; } double averageFPS = 0; double averageFrameMs = 0; if (m_fpsHistory.size() > 1) { - deltaTime = m_fpsHistory.back().m_beginFrameTime - m_fpsHistory.front().m_beginFrameTime; - averageFPS = AZStd::chrono::seconds(m_fpsHistory.size() - 1) / deltaTime; - averageFrameMs = aznumeric_cast(totalFrameMS.count()) / (m_fpsHistory.size() - 1); + deltaTime = m_fpsHistory.back() - m_fpsHistory.front(); + averageFPS = AZStd::chrono::seconds(m_fpsHistory.size()) / deltaTime; + averageFrameMs = 1000.0f/averageFPS; } const double frameIntervalSeconds = m_fpsInterval.count(); @@ -303,7 +288,7 @@ namespace AZ::Render AZStd::string::format( "FPS %.1f [%.0f..%.0f], %.1fms/frame, avg over %.1fs", averageFPS, - minFPS == DBL_MAX ? 0.0 : minFPS, + minFPS, maxFPS, averageFrameMs, frameIntervalSeconds), diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h index 689cfdb43b..1d53e188d0 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h @@ -45,7 +45,6 @@ namespace AZ // AZ::RPI::ViewportContextNotificationBus::Handler overrides... void OnRenderTick() override; - void OnFrameEnd() override; // AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler overrides... AtomBridge::ViewportInfoDisplayState GetDisplayState() const override; @@ -62,8 +61,6 @@ namespace AZ void DrawPassInfo(); void DrawFramerate(); - void UpdateScene(AZ::RPI::ScenePtr scene); - static constexpr float BaseFontSize = 0.7f; AZStd::string m_rendererDescription; @@ -71,17 +68,7 @@ namespace AZ AzFramework::FontDrawInterface* m_fontDrawInterface = nullptr; float m_lineSpacing; AZStd::chrono::duration m_fpsInterval = AZStd::chrono::seconds(1); - struct FrameTimingInfo - { - AZStd::chrono::system_clock::time_point m_beginFrameTime; - AZStd::optional m_endFrameTime; - - explicit FrameTimingInfo(AZStd::chrono::system_clock::time_point beginFrameTime) - : m_beginFrameTime(beginFrameTime) - { - } - }; - AZStd::deque m_fpsHistory; + AZStd::deque m_fpsHistory; AZStd::optional m_lastMemoryUpdate; bool m_updateRootPassQuery = true; }; From e76ed67e950e5abd375ccfef1b551eb334d9e060 Mon Sep 17 00:00:00 2001 From: nggieber Date: Tue, 21 Sep 2021 18:34:15 -0700 Subject: [PATCH 035/115] Add no repositories added screen Signed-off-by: nggieber --- .../Resources/ProjectManager.qss | 11 +- .../Source/GemRepo/GemRepoAddDialog.cpp | 18 +++ .../Source/GemRepo/GemRepoAddDialog.h | 24 +++ .../Source/GemRepo/GemRepoScreen.cpp | 139 +++++++++++++----- .../Source/GemRepo/GemRepoScreen.h | 8 + .../project_manager_files.cmake | 2 + 6 files changed, 164 insertions(+), 38 deletions(-) create mode 100644 Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp create mode 100644 Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 30117d6636..52cc784336 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -556,17 +556,20 @@ QProgressBar::chunk { font-size: 12px; } +#gemRepoNoReposLabel { + font-size: 16px; +} + #gemRepoHeaderRefreshButton { background-color: transparent; qproperty-flat: true; qproperty-iconSize: 14px; } -#gemRepoHeaderAddButton { +#gemRepoAddButton { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #888888, stop: 1.0 #555555); qproperty-flat: true; - margin-right:30px; min-width:120px; max-width:120px; min-height:24px; @@ -576,11 +579,11 @@ QProgressBar::chunk { font-size:12px; font-weight:600; } -#gemRepoHeaderAddButton:hover { +#gemRepoAddButton:hover { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #999999, stop: 1.0 #666666); } -#gemRepoHeaderAddButton:pressed { +#gemRepoAddButton:pressed { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #555555, stop: 1.0 #777777); } diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp new file mode 100644 index 0000000000..31e98a965b --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp @@ -0,0 +1,18 @@ +/* + * 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 O3DE::ProjectManager +{ + GemRepoAddDialog::GemRepoAddDialog(QWidget* parent) + : QDialog(parent) + { + + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h new file mode 100644 index 0000000000..24c9b4b357 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h @@ -0,0 +1,24 @@ +/* + * 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 O3DE::ProjectManager +{ + class GemRepoAddDialog + : public QDialog + { + public: + explicit GemRepoAddDialog(QWidget* parent = nullptr); + ~GemRepoAddDialog() = default; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 82de53a0d0..5838abf643 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include namespace O3DE::ProjectManager { @@ -31,12 +33,109 @@ namespace O3DE::ProjectManager QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); vLayout->setSpacing(0); - setLayout(vLayout); + setLayout(vLayout); + + m_contentStack = new QStackedWidget(this); + + m_noRepoContent = CreateNoReposContent(); + m_contentStack->addWidget(m_noRepoContent); + + m_repoContent = CreateReposContent(); + m_contentStack->addWidget(m_repoContent); + + vLayout->addWidget(m_contentStack); + + Reinit(); + } + + void GemRepoScreen::Reinit() + { + m_gemRepoModel->clear(); + FillModel(); + + // If model contains any data show the repos + if (m_gemRepoModel->rowCount()) + { + m_contentStack->setCurrentWidget(m_repoContent); + } + else + { + m_contentStack->setCurrentWidget(m_noRepoContent); + } + + // Select the first entry after everything got correctly sized + QTimer::singleShot(200, [=]{ + QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0); + m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); + }); + } + + void GemRepoScreen::FillModel() + { + AZ::Outcome, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos(); + if (allGemRepoInfosResult.IsSuccess()) + { + // Add all available repos to the model + const QVector allGemRepoInfos = allGemRepoInfosResult.GetValue(); + for (const GemRepoInfo& gemRepoInfo : allGemRepoInfos) + { + m_gemRepoModel->AddGemRepo(gemRepoInfo); + } + } + else + { + QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str())); + } + } + + QFrame* GemRepoScreen::CreateNoReposContent() + { + QFrame* contentFrame = new QFrame(this); + + QVBoxLayout* vLayout = new QVBoxLayout(); + vLayout->setAlignment(Qt::AlignHCenter); + vLayout->setMargin(0); + vLayout->setSpacing(0); + contentFrame->setLayout(vLayout); + + vLayout->addStretch(); + + QLabel* noRepoLabel = new QLabel(tr("No repositories have been added yet."), this); + noRepoLabel->setObjectName("gemRepoNoReposLabel"); + vLayout->addWidget(noRepoLabel); + vLayout->setAlignment(noRepoLabel, Qt::AlignHCenter); + + vLayout->addSpacing(20); + + // Size hint for button is wrong so horizontal layout with stretch is used to center it + QHBoxLayout* hLayout = new QHBoxLayout(); + hLayout->setMargin(0); + hLayout->setSpacing(0); + + hLayout->addStretch(); + + m_AddRepoButton = new QPushButton(tr("Add Repository"), this); + m_AddRepoButton->setObjectName("gemRepoAddButton"); + m_AddRepoButton->setMinimumWidth(120); + hLayout->addWidget(m_AddRepoButton); + + hLayout->addStretch(); + + vLayout->addLayout(hLayout); + + vLayout->addStretch(); + + return contentFrame; + } + + QFrame* GemRepoScreen::CreateReposContent() + { + QFrame* contentFrame = new QFrame(this); QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setMargin(0); hLayout->setSpacing(0); - vLayout->addLayout(hLayout); + contentFrame->setLayout(hLayout); hLayout->addSpacing(60); @@ -67,9 +166,11 @@ namespace O3DE::ProjectManager topMiddleHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); m_AddRepoButton = new QPushButton(tr("Add Repository"), this); - m_AddRepoButton->setObjectName("gemRepoHeaderAddButton"); + m_AddRepoButton->setObjectName("gemRepoAddButton"); topMiddleHLayout->addWidget(m_AddRepoButton); + topMiddleHLayout->addSpacing(30); + middleVLayout->addLayout(topMiddleHLayout); middleVLayout->addSpacing(30); @@ -105,37 +206,7 @@ namespace O3DE::ProjectManager hLayout->addLayout(middleVLayout); hLayout->addWidget(m_gemRepoInspector); - Reinit(); - } - - void GemRepoScreen::Reinit() - { - m_gemRepoModel->clear(); - FillModel(); - - // Select the first entry after everything got correctly sized - QTimer::singleShot(200, [=]{ - QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0); - m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); - }); - } - - void GemRepoScreen::FillModel() - { - AZ::Outcome, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos(); - if (allGemRepoInfosResult.IsSuccess()) - { - // Add all available repos to the model - const QVector allGemRepoInfos = allGemRepoInfosResult.GetValue(); - for (const GemRepoInfo& gemRepoInfo : allGemRepoInfos) - { - m_gemRepoModel->AddGemRepo(gemRepoInfo); - } - } - else - { - QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str())); - } + return contentFrame; } ProjectManagerScreen GemRepoScreen::GetScreenEnum() diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h index b5316db84f..ab679ad39b 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h @@ -16,6 +16,8 @@ QT_FORWARD_DECLARE_CLASS(QLabel) QT_FORWARD_DECLARE_CLASS(QPushButton) QT_FORWARD_DECLARE_CLASS(QHeaderView) QT_FORWARD_DECLARE_CLASS(QTableWidget) +QT_FORWARD_DECLARE_CLASS(QFrame) +QT_FORWARD_DECLARE_CLASS(QStackedWidget) namespace O3DE::ProjectManager { @@ -36,6 +38,12 @@ namespace O3DE::ProjectManager private: void FillModel(); + QFrame* CreateNoReposContent(); + QFrame* CreateReposContent(); + + QStackedWidget* m_contentStack = nullptr; + QFrame* m_noRepoContent; + QFrame* m_repoContent; QTableWidget* m_gemRepoHeaderTable = nullptr; QHeaderView* m_gemRepoListHeader = nullptr; diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 7a336972e0..31686faa2f 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -102,6 +102,8 @@ set(FILES Source/GemCatalog/GemSortFilterProxyModel.cpp Source/GemRepo/GemRepoScreen.h Source/GemRepo/GemRepoScreen.cpp + Source/GemRepo/GemRepoAddDialog.h + Source/GemRepo/GemRepoAddDialog.cpp Source/GemRepo/GemRepoInfo.h Source/GemRepo/GemRepoInfo.cpp Source/GemRepo/GemRepoItemDelegate.h From beaa90a96886baace124f79267354d8e60e14c37 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 22 Sep 2021 16:24:33 +0100 Subject: [PATCH 036/115] Call sites for editor mode activate/deactivate. Signed-off-by: John --- AutomatedTesting/Levels/Floof/Floof.ly | 3 ++ AutomatedTesting/Levels/Floof/filelist.xml | 6 ++++ AutomatedTesting/Levels/Floof/level.pak | 3 ++ AutomatedTesting/Levels/Floof/tags.txt | 12 +++++++ .../ComponentMode/ComponentModeCollection.cpp | 4 +-- .../PropertyEditor/PropertyEntityIdCtrl.cpp | 5 +-- .../UnitTest/AzToolsFrameworkTestHelpers.h | 4 ++- .../EditorDefaultSelection.cpp | 32 +++++++++++++++++++ .../EditorDefaultSelection.h | 5 +++ .../EditorInteractionSystemComponent.cpp | 28 +++++++++++++--- .../EditorInteractionSystemComponent.h | 15 +++++++++ ...ractionSystemViewportSelectionRequestBus.h | 5 +-- .../EditorPickEntitySelection.cpp | 17 ++++++++++ .../EditorPickEntitySelection.h | 7 +++- .../ViewportEditorModeTracker.cpp | 16 ---------- .../ViewportEditorModeTracker.h | 6 ---- ...EditorTransformComponentSelectionTests.cpp | 3 +- .../Viewport/ViewportEditorModeTests.cpp | 22 +++++++++---- 18 files changed, 152 insertions(+), 41 deletions(-) create mode 100644 AutomatedTesting/Levels/Floof/Floof.ly create mode 100644 AutomatedTesting/Levels/Floof/filelist.xml create mode 100644 AutomatedTesting/Levels/Floof/level.pak create mode 100644 AutomatedTesting/Levels/Floof/tags.txt diff --git a/AutomatedTesting/Levels/Floof/Floof.ly b/AutomatedTesting/Levels/Floof/Floof.ly new file mode 100644 index 0000000000..aa7ed0d9db --- /dev/null +++ b/AutomatedTesting/Levels/Floof/Floof.ly @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3473284ee7f390280fb71090da8c1754791a3753fc1532e6b6a69842f2d4e23f +size 8605 diff --git a/AutomatedTesting/Levels/Floof/filelist.xml b/AutomatedTesting/Levels/Floof/filelist.xml new file mode 100644 index 0000000000..82409c84cd --- /dev/null +++ b/AutomatedTesting/Levels/Floof/filelist.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/AutomatedTesting/Levels/Floof/level.pak b/AutomatedTesting/Levels/Floof/level.pak new file mode 100644 index 0000000000..e9374fe73f --- /dev/null +++ b/AutomatedTesting/Levels/Floof/level.pak @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9577257254e5938790ec3445689a9b59bc1715c7f1aaaad81150b9468e72cbfa +size 1346 diff --git a/AutomatedTesting/Levels/Floof/tags.txt b/AutomatedTesting/Levels/Floof/tags.txt new file mode 100644 index 0000000000..0d6c1880e7 --- /dev/null +++ b/AutomatedTesting/Levels/Floof/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 diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index 0259142135..5527a35f88 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -8,8 +8,8 @@ #include "ComponentModeCollection.h" -#include #include +#include namespace AzToolsFramework { @@ -17,7 +17,7 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(ComponentModeCollection, AZ::SystemAllocator, 0) - static const char* const s_nextActiveComponentModeTitle = "Edit Next"; + static const char* const s_nextActiveComponentModeTitle = "Edit Next"; static const char* const s_previousActiveComponentModeTitle = "Edit Previous"; static const char* const s_nextActiveComponentModeDesc = "Move to the next component"; static const char* const s_prevActiveComponentModeDesc = "Move to the previous component"; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp index f98638fd69..7a9a5a4d7a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp @@ -119,11 +119,12 @@ namespace AzToolsFramework // replace the default input handler with one specific for dealing with // entity selection in the viewport + EditorInteractionSystemViewportSelectionRequestBus::Event( GetEntityContextId(), &EditorInteractionSystemViewportSelection::SetHandler, - [](const EditorVisibleEntityDataCache* entityDataCache) + [](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); if (!pickModeEntityContextId.IsNull()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h index b3a660d0f2..a67562af76 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -166,7 +167,8 @@ namespace UnitTest m_editorActions.Connect(); const auto viewportHandlerBuilder = - [this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache) + [this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { // create the default viewport (handles ComponentMode) AZStd::unique_ptr defaultSelection = diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index 7903668409..0b23756365 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -9,6 +9,7 @@ #include "EditorDefaultSelection.h" #include +#include #include #include #include @@ -30,10 +31,25 @@ namespace AzToolsFramework m_transformComponentSelection = AZStd::make_unique(entityDataCache); } + EditorDefaultSelection::EditorDefaultSelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + : EditorDefaultSelection(entityDataCache) + { + m_viewportEditorModeTracker = viewportEditorModeTracker; + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); + } + } + EditorDefaultSelection::~EditorDefaultSelection() { ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusDisconnect(); ActionOverrideRequestBus::Handler::BusDisconnect(); + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); + } } void EditorDefaultSelection::SetOverridePhantomWidget(QWidget* phantomOverrideWidget) @@ -91,6 +107,14 @@ namespace AzToolsFramework m_componentModeCollection.BeginComponentMode(); + // this call to activate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); + } + // refresh button ui ToolsApplicationEvents::Bus::Broadcast( &ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay, PropertyModificationRefreshLevel::Refresh_EntireTree); @@ -100,6 +124,14 @@ namespace AzToolsFramework { m_componentModeCollection.EndComponentMode(); + // this call to deactivate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); + } + if (m_transformComponentSelection) { // safe to show manipulators again diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h index 5763bf227c..6a53a2b186 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h @@ -15,6 +15,8 @@ namespace AzToolsFramework { + class ViewportEditorModeTrackerInterface; + //! The default selection/input handler for the editor (includes handling ComponentMode). class EditorDefaultSelection : public ViewportInteraction::InternalViewportSelectionRequests @@ -26,6 +28,7 @@ namespace AzToolsFramework //! @cond explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache); + explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); EditorDefaultSelection(const EditorDefaultSelection&) = delete; EditorDefaultSelection& operator=(const EditorDefaultSelection&) = delete; virtual ~EditorDefaultSelection(); @@ -110,5 +113,7 @@ namespace AzToolsFramework AZStd::shared_ptr m_manipulatorManager; //!< The default manipulator manager. ViewportInteraction::MouseInteraction m_currentInteraction; //!< Current mouse interaction to be used for drawing manipulators. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. + }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp index 7002436d13..7f84038ace 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp @@ -10,9 +10,28 @@ #include #include +#include namespace AzToolsFramework { + EditorInteractionSystemComponent::EditorInteractionSystemComponent() + : m_viewportEditorMode(AZStd::make_unique()) + { + if (AZ::Interface::Get() == nullptr) + { + AZ::Interface::Register(m_viewportEditorMode.get()); + } + } + + EditorInteractionSystemComponent::~EditorInteractionSystemComponent() + { + m_interactionRequests.reset(); + if (AZ::Interface::Get() != nullptr) + { + AZ::Interface::Unregister(m_viewportEditorMode.get()); + } + } + void EditorInteractionSystemComponent::Activate() { EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId()); @@ -41,7 +60,8 @@ namespace AzToolsFramework return m_interactionRequests->InternalHandleMouseManipulatorInteraction(mouseInteraction); } - void EditorInteractionSystemComponent::SetHandler(const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) + void EditorInteractionSystemComponent::SetHandler( + const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) { // when setting a handler, make sure we're connected to the ViewportDebugDisplayEventBus so we // can forward calls to the specific type implementing ViewportSelectionRequests @@ -59,7 +79,7 @@ namespace AzToolsFramework m_entityDataCache = AZStd::make_unique(); m_interactionRequests.reset(); // BusConnect/Disconnect in constructor/destructor, // so have to reset before assigning the new one - m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get()); + m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get(), m_viewportEditorMode.get()); } EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId()); @@ -68,9 +88,9 @@ namespace AzToolsFramework void EditorInteractionSystemComponent::SetDefaultHandler() { SetHandler( - [](const EditorVisibleEntityDataCache* entityDataCache) + [](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h index 17521eab14..7bbc0ee009 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h @@ -12,8 +12,18 @@ #include #include + + + + + + +#include + namespace AzToolsFramework { + //class ViewportEditorModeTracker; + //! System Component to wrap active input handler. //! EditorInteractionSystemComponent is notified of viewport mouse events from RenderViewport //! and forwards them to a concrete implementation of ViewportSelectionRequests. @@ -26,6 +36,9 @@ namespace AzToolsFramework public: AZ_COMPONENT(EditorInteractionSystemComponent, "{146D0317-AF42-45AB-A953-F54198525DD5}") + EditorInteractionSystemComponent(); + ~EditorInteractionSystemComponent(); + static void Reflect(AZ::ReflectContext* context); // EditorInteractionSystemViewportSelectionRequestBus @@ -54,5 +67,7 @@ namespace AzToolsFramework AZStd::unique_ptr m_interactionRequests; //!< Hold a concrete implementation of //!< ViewportSelectionRequests to handle viewport //!< input and drawing for the Editor. + + AZStd::unique_ptr m_viewportEditorMode; //!< Editor mode tracker for each viewport. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h index ee3f83f74d..3579460ca0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h @@ -17,6 +17,7 @@ namespace AzToolsFramework { class EditorVisibleEntityDataCache; + class ViewportEditorModeTrackerInterface; //! Bus to handle all mouse events originating from the viewport. //! Coordinated by the EditorInteractionSystemComponent @@ -32,8 +33,8 @@ namespace AzToolsFramework }; //! Alias for factory function to create a new type implementing the ViewportSelectionRequests interface. - using ViewportSelectionRequestsBuilderFn = - AZStd::function(const EditorVisibleEntityDataCache*)>; + using ViewportSelectionRequestsBuilderFn = AZStd::function( + const EditorVisibleEntityDataCache*, ViewportEditorModeTrackerInterface*)>; //! Interface for system component implementing the ViewportSelectionRequests interface. //! This interface also includes a setter to set a custom handler also implementing diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp index ea1bc73056..9306deb69d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp @@ -8,6 +8,7 @@ #include "EditorPickEntitySelection.h" +#include #include #include @@ -20,12 +21,28 @@ namespace AzToolsFramework { } + EditorPickEntitySelection::EditorPickEntitySelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + : EditorPickEntitySelection(entityDataCache) + { + m_viewportEditorModeTracker = viewportEditorModeTracker; + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); + } + } + EditorPickEntitySelection::~EditorPickEntitySelection() { if (m_hoveredEntityId.IsValid()) { ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, m_hoveredEntityId, false); } + + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); + } } // note: entityIdUnderCursor is the authoritative entityId we get each frame by querying diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h index e8d83af932..511111743a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h @@ -13,6 +13,8 @@ namespace AzToolsFramework { + class ViewportEditorModeTrackerInterface; + //! Viewport interaction that will handle assigning an entity in the viewport to //! an entity field in the entity inspector. class EditorPickEntitySelection : public ViewportInteraction::InternalViewportSelectionRequests @@ -20,7 +22,9 @@ namespace AzToolsFramework public: AZ_CLASS_ALLOCATOR_DECL - EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache); + explicit EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache); + explicit EditorPickEntitySelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~EditorPickEntitySelection(); private: @@ -32,5 +36,6 @@ namespace AzToolsFramework AZStd::unique_ptr m_editorHelpers; //!< Editor visualization of entities (icons, shapes, debug visuals etc). AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any). AZ::EntityId m_cachedEntityIdUnderCursor; //!< Store the EntityId on each mouse move for use in Display. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 4adddb02e1..105712c789 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -45,22 +45,6 @@ namespace AzToolsFramework return m_editorModes[static_cast(mode)]; } - void ViewportEditorModeTracker::RegisterInterface() - { - if (AZ::Interface::Get() == nullptr) - { - AZ::Interface::Register(this); - } - } - - void ViewportEditorModeTracker::UnregisterInterface() - { - if (AZ::Interface::Get() != nullptr) - { - AZ::Interface::Unregister(this); - } - } - AZ::Outcome ViewportEditorModeTracker::ActivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 6ae68b39b2..5b382c44e7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -41,12 +41,6 @@ namespace AzToolsFramework : public ViewportEditorModeTrackerInterface { public: - //! Registers this object with the AZ::Interface. - void RegisterInterface(); - - //! Unregisters this object with the AZ::Interface. - void UnregisterInterface(); - // ViewportEditorModeTrackerInterface overrides ... AZ::Outcome ActivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; AZ::Outcome DeactivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index 449c4549be..1316523f29 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -343,7 +343,8 @@ namespace UnitTest using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus; EditorInteractionSystemViewportSelectionRequestBus::Event( AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, - [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache) + [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { return AZStd::make_unique(entityDataCache); }); diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 3954ef6dc6..b2b75e22a7 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -152,6 +152,12 @@ namespace UnitTest AZStd::array, ViewportEditorModes::NumEditorModes> m_editorModeHandlers; }; + // Fixture for testing the integration of viewport editor mode state tracker + class ViewportEditorModeTrackerIntegrationTestFixture + : public ToolsApplicationFixture + { + }; + TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4) { EXPECT_EQ(ViewportEditorModes::NumEditorModes, 4); @@ -298,7 +304,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetTrackedViewportCount(), 0); } - TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) + TEST_F(ViewportEditorModeTrackerTestFixture, ActivatingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -318,7 +324,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError) + TEST_F(ViewportEditorModeTrackerTestFixture, DeactivatingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -351,7 +357,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); } - TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateReturnsError) + TEST_F(ViewportEditorModeTrackerTestFixture, ActivatingViewportEditorModesForExistingIdInThatStateReturnsError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -390,7 +396,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateReturnssError) + TEST_F(ViewportEditorModeTrackerTestFixture, DeactivatingViewportEditorModesForExistingIdNotInThatStateReturnssError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -432,7 +438,7 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - RegisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeRegisterEventForAllSubscribers) + ActivatingViewportEditorModesForExistingIdPublishesOnViewportEditorModeActivateEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -465,7 +471,7 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - UnregisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeUnregisterEventForAllSubscribers) + DeactivatingViewportEditorModesForExistingIdPublishesOnViewportEditorModeDeactivatingEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -495,4 +501,8 @@ namespace UnitTest EXPECT_TRUE(expectedEditorModeSet->second.m_onExit); } } + + TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, FOO) + { + } } // namespace UnitTest From 4909c91614389d48db63e4216a3f4a4ed2ae8389 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 22 Sep 2021 16:46:44 +0100 Subject: [PATCH 037/115] Move Component editor mode logic to ComponentModeCollection. Signed-off-by: John --- .../ComponentMode/ComponentModeCollection.cpp | 21 +++++++++++++++++++ .../ComponentMode/ComponentModeCollection.h | 3 +++ .../EditorDefaultSelection.cpp | 16 -------------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index 5527a35f88..dddaa679bf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -9,6 +9,7 @@ #include "ComponentModeCollection.h" #include +#include #include namespace AzToolsFramework @@ -119,6 +120,11 @@ namespace AzToolsFramework } }; + ComponentModeCollection::ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + : m_viewportEditorModeTracker(viewportEditorModeTracker) + { + } + void ComponentModeCollection::AddComponentMode( const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid componentType, const ComponentModeFactoryFunction& componentModeBuilder) @@ -209,6 +215,14 @@ namespace AzToolsFramework GetEntityContextId(), &EditorComponentModeNotifications::EnteredComponentMode, m_activeComponentTypes); + // this call to activate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); + } + // enable actions for the first/primary ComponentMode // note: if multiple ComponentModes are activated at the same time, actions // are not available together, the 'active' mode will bind its actions one at a time @@ -282,6 +296,13 @@ namespace AzToolsFramework &EditorComponentModeNotifications::LeftComponentMode, m_activeComponentTypes); + // this call to deactivate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); + } // clear stored modes and builders for this ComponentMode // TLDR: avoid 'use after free' error diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h index 7dd97dc0c9..b295d6103b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h @@ -15,6 +15,7 @@ namespace AzToolsFramework { class EditorMetricsEventsBusTraits; + class ViewportEditorModeTrackerInterface; namespace ComponentModeFramework { @@ -26,6 +27,7 @@ namespace AzToolsFramework /// @cond ComponentModeCollection() = default; + ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~ComponentModeCollection() = default; ComponentModeCollection(const ComponentModeCollection&) = delete; ComponentModeCollection& operator=(const ComponentModeCollection&) = delete; @@ -101,6 +103,7 @@ namespace AzToolsFramework size_t m_selectedComponentModeIndex = 0; ///< Index into the array of active ComponentModes, current index is 'selected' ComponentMode. bool m_adding = false; ///< Are we currently adding individual ComponentModes to the Editor wide ComponentMode. bool m_componentMode = false; ///< Editor (global) ComponentMode flag - is ComponentMode active or not. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. }; } // namespace ComponentModeFramework } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index 0b23756365..321549585a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -107,14 +107,6 @@ namespace AzToolsFramework m_componentModeCollection.BeginComponentMode(); - // this call to activate the component mode editor state should eventually replace the bus call in - // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode - // such that all of the notifications for activating/deactivating the different editor modes are in a central location - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); - } - // refresh button ui ToolsApplicationEvents::Bus::Broadcast( &ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay, PropertyModificationRefreshLevel::Refresh_EntireTree); @@ -124,14 +116,6 @@ namespace AzToolsFramework { m_componentModeCollection.EndComponentMode(); - // this call to deactivate the component mode editor state should eventually replace the bus call in - // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode - // such that all of the notifications for activating/deactivating the different editor modes are in a central location - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); - } - if (m_transformComponentSelection) { // safe to show manipulators again From 071d3eaa311046d2850a7957b74e5d475c220a54 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 22 Sep 2021 16:49:22 +0100 Subject: [PATCH 038/115] Delete non-source data. Signed-off-by: John --- AutomatedTesting/Levels/Floof/Floof.ly | 3 --- AutomatedTesting/Levels/Floof/filelist.xml | 6 ------ AutomatedTesting/Levels/Floof/level.pak | 3 --- AutomatedTesting/Levels/Floof/tags.txt | 12 ------------ 4 files changed, 24 deletions(-) delete mode 100644 AutomatedTesting/Levels/Floof/Floof.ly delete mode 100644 AutomatedTesting/Levels/Floof/filelist.xml delete mode 100644 AutomatedTesting/Levels/Floof/level.pak delete mode 100644 AutomatedTesting/Levels/Floof/tags.txt diff --git a/AutomatedTesting/Levels/Floof/Floof.ly b/AutomatedTesting/Levels/Floof/Floof.ly deleted file mode 100644 index aa7ed0d9db..0000000000 --- a/AutomatedTesting/Levels/Floof/Floof.ly +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3473284ee7f390280fb71090da8c1754791a3753fc1532e6b6a69842f2d4e23f -size 8605 diff --git a/AutomatedTesting/Levels/Floof/filelist.xml b/AutomatedTesting/Levels/Floof/filelist.xml deleted file mode 100644 index 82409c84cd..0000000000 --- a/AutomatedTesting/Levels/Floof/filelist.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/AutomatedTesting/Levels/Floof/level.pak b/AutomatedTesting/Levels/Floof/level.pak deleted file mode 100644 index e9374fe73f..0000000000 --- a/AutomatedTesting/Levels/Floof/level.pak +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9577257254e5938790ec3445689a9b59bc1715c7f1aaaad81150b9468e72cbfa -size 1346 diff --git a/AutomatedTesting/Levels/Floof/tags.txt b/AutomatedTesting/Levels/Floof/tags.txt deleted file mode 100644 index 0d6c1880e7..0000000000 --- a/AutomatedTesting/Levels/Floof/tags.txt +++ /dev/null @@ -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,0,0 From 15e6d999c2a61f97b56f5b79f4db0e21eac62c8a Mon Sep 17 00:00:00 2001 From: John Date: Wed, 22 Sep 2021 16:53:01 +0100 Subject: [PATCH 039/115] Remove line breaks and forward declare class. Signed-off-by: John --- .../EditorInteractionSystemComponent.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h index 7bbc0ee009..856fd2e326 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h @@ -12,17 +12,9 @@ #include #include - - - - - - -#include - namespace AzToolsFramework { - //class ViewportEditorModeTracker; + class ViewportEditorModeTracker; //! System Component to wrap active input handler. //! EditorInteractionSystemComponent is notified of viewport mouse events from RenderViewport From 8ab409e4d257e4d8d1ee12b16437e3069fce5992 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Mon, 20 Sep 2021 23:36:41 -0700 Subject: [PATCH 040/115] Implemented the PrefabViewportFocusPathHandler class, added a breadcrumb widget to the viewport toolbar to display the currently focused prefab path. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- Code/Editor/ViewportTitleDlg.cpp | 4 +- Code/Editor/ViewportTitleDlg.h | 3 + Code/Editor/ViewportTitleDlg.ui | 29 +++++--- .../Prefab/PrefabFocusHandler.cpp | 68 ++++++++++++++++++- .../Prefab/PrefabFocusHandler.h | 11 +++ .../Prefab/PrefabFocusInterface.h | 9 +++ .../Prefab/PrefabFocusNotificationBus.h | 25 +++++++ .../Prefab/PrefabViewportFocusPathHandler.cpp | 54 +++++++++++++++ .../Prefab/PrefabViewportFocusPathHandler.h | 40 +++++++++++ .../aztoolsframework_files.cmake | 3 + 10 files changed, 231 insertions(+), 15 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 65d6de8944..0c5c45e5c8 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -292,8 +292,6 @@ void CViewportTitleDlg::SetViewPane(CLayoutViewPane* pViewPane) ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::OnInitDialog() { - m_ui->m_titleBtn->setText(m_title); - // Add a child parented to us that listens for r_displayInfo changes. auto displayInfoHelper = new CViewportTitleDlgDisplayInfoHelper(this); connect(displayInfoHelper, &CViewportTitleDlgDisplayInfoHelper::ViewportInfoStatusUpdated, this, &CViewportTitleDlg::UpdateDisplayInfo); @@ -314,13 +312,13 @@ void CViewportTitleDlg::OnInitDialog() m_cameraSpeed->setFixedWidth(width); + m_prefabViewportFocusPathHandler.Initialize(m_ui->m_prefabFocusPath, m_ui->m_prefabFocusBackButton); } ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::SetTitle(const QString& title) { m_title = title; - m_ui->m_titleBtn->setText(m_title); } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/ViewportTitleDlg.h b/Code/Editor/ViewportTitleDlg.h index 4a2a454907..dfdf567a39 100644 --- a/Code/Editor/ViewportTitleDlg.h +++ b/Code/Editor/ViewportTitleDlg.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -176,6 +177,8 @@ protected: QWidgetAction* m_gridSizeActionWidget = nullptr; QWidgetAction* m_angleSizeActionWidget = nullptr; + AzToolsFramework::Prefab::PrefabViewportFocusPathHandler m_prefabViewportFocusPathHandler; + QScopedPointer m_ui; }; diff --git a/Code/Editor/ViewportTitleDlg.ui b/Code/Editor/ViewportTitleDlg.ui index f0679dd2a1..e67f04b68a 100644 --- a/Code/Editor/ViewportTitleDlg.ui +++ b/Code/Editor/ViewportTitleDlg.ui @@ -42,22 +42,25 @@ 0 - + + + + :/Breadcrumb/img/UI20/Breadcrumb/arrow_left-default.svg:/Breadcrumb/img/UI20/Breadcrumb/arrow_left-default.svg + + + + Back + + + + + 0 0 - - Qt::NoContextMenu - - - Static - - - 11 - @@ -129,6 +132,12 @@ + + AzQtComponents::BreadCrumbs + QWidget +
AzQtComponents/Components/Widgets/Breadcrumbs.h
+ 1 +
AzQtComponents::ButtonDivider QWidget diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 2338c8892b..276d76f848 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace AzToolsFramework::Prefab { @@ -23,12 +24,14 @@ namespace AzToolsFramework::Prefab "Instance Entity Mapper Interface could not be found. " "Check that it is being correctly initialized."); + EditorEntityContextNotificationBus::Handler::BusConnect(); AZ::Interface::Register(this); } PrefabFocusHandler::~PrefabFocusHandler() { AZ::Interface::Unregister(this); + EditorEntityContextNotificationBus::Handler::BusDisconnect(); } PrefabFocusOperationResult PrefabFocusHandler::FocusOnOwningPrefab(AZ::EntityId entityId) @@ -55,8 +58,28 @@ namespace AzToolsFramework::Prefab if (!focusedInstance.has_value()) { - return AZ::Failure(AZStd::string( - "Prefab Focus Handler: Couldn't find owning instance of entityId provided.")); + return AZ::Failure(AZStd::string("Prefab Focus Handler: Couldn't find owning instance of entityId provided.")); + } + + if (&m_focusedInstance->get() != &focusedInstance->get()) + { + m_focusedInstance = focusedInstance; + m_focusedTemplateId = focusedInstance->get().GetTemplateId(); + s_focusModeInterface->SetFocusRoot(focusedInstance->get().GetContainerEntityId()); + + RefreshInstanceFocusList(); + + PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); + } + + return AZ::Success(); + } + + PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex(int index) + { + if (index < 0 || index >= m_instanceFocusVector.size()) + { + return AZ::Failure(AZStd::string("Prefab Focus Handler: Invalid index on FocusOnPathIndex.")); } m_focusedInstance = focusedInstance; @@ -68,7 +91,13 @@ namespace AzToolsFramework::Prefab focusModeInterface->SetFocusRoot(focusedInstance->get().GetContainerEntityId()); } + RefreshInstanceFocusList(); + + PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); + } + return AZ::Success(); + } TemplateId PrefabFocusHandler::GetFocusedPrefabTemplateId() @@ -93,4 +122,39 @@ namespace AzToolsFramework::Prefab return instance.has_value() && (&instance->get() == &m_focusedInstance->get()); } + const AZ::IO::Path& PrefabFocusHandler::GetPrefabFocusPath() + { + return m_instanceFocusPath; + } + + void PrefabFocusHandler::OnEntityStreamLoadSuccess() + { + // Focus on the root prefab (AZ::EntityId() will default to it) + FocusOnOwningPrefab(AZ::EntityId()); + } + + void PrefabFocusHandler::RefreshInstanceFocusList() + { + m_instanceFocusVector.clear(); + m_instanceFocusPath.clear(); + + AZStd::list instanceFocusList; + + // Use a support list to easily push front while traversing the prefab hierarchy + InstanceOptionalReference currentInstance = m_focusedInstance; + while (currentInstance.has_value()) + { + instanceFocusList.push_front(currentInstance); + + currentInstance = currentInstance->get().GetParentInstance(); + } + + // Populate internals using the support list + for (auto& instance : instanceFocusList) + { + m_instanceFocusPath.Append(instance->get().GetContainerEntity()->get().GetName()); + m_instanceFocusVector.emplace_back(instance); + } + } + } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index fa7727894d..35ef9aba61 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -21,6 +22,7 @@ namespace AzToolsFramework::Prefab //! Handles Prefab Focus mode, determining which prefab file entity changes will target. class PrefabFocusHandler final : private PrefabFocusInterface + , private EditorEntityContextNotificationBus::Handler { public: AZ_CLASS_ALLOCATOR(PrefabFocusHandler, AZ::SystemAllocator, 0); @@ -30,13 +32,22 @@ namespace AzToolsFramework::Prefab // PrefabFocusInterface override ... PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override; + PrefabFocusOperationResult FocusOnPathIndex(int index) override; TemplateId GetFocusedPrefabTemplateId() override; InstanceOptionalReference GetFocusedPrefabInstance() override; bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) override; + const AZ::IO::Path& GetPrefabFocusPath() override; + + // EditorEntityContextNotificationBus... + void OnEntityStreamLoadSuccess() override; private: + void RefreshInstanceFocusList(); + InstanceOptionalReference m_focusedInstance; TemplateId m_focusedTemplateId; + AZStd::vector m_instanceFocusVector; + AZ::IO::Path m_instanceFocusPath; InstanceEntityMapperInterface* m_instanceEntityMapperInterface; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h index 833a5ef7c8..9f695f2bf7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h @@ -28,6 +28,10 @@ namespace AzToolsFramework::Prefab //! @param entityId The entityId of the entity whose owning instance we want the prefab system to focus on. virtual PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) = 0; + //! Set the focused prefab instance to the instance at position index of the current path. + //! @param index The index of the instance in the current path that we want the prefab system to focus on. + virtual PrefabFocusOperationResult FocusOnPathIndex(int index) = 0; + //! Returns the template id of the instance the prefab system is focusing on. virtual TemplateId GetFocusedPrefabTemplateId() = 0; @@ -38,6 +42,11 @@ namespace AzToolsFramework::Prefab //! @param entityId The entityId of the queried entity. //! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise. virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) = 0; + + //! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants. + //! @param entityId The entityId of the queried entity. + //! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise. + virtual const AZ::IO::Path& GetPrefabFocusPath() = 0; }; } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h new file mode 100644 index 0000000000..5eda6ff2e3 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h @@ -0,0 +1,25 @@ +/* + * 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 AzToolsFramework::Prefab +{ + class PrefabFocusNotifications : public AZ::EBusTraits + { + public: + virtual ~PrefabFocusNotifications() = default; + + virtual void OnPrefabFocusChanged() = 0; + }; + + using PrefabFocusNotificationBus = AZ::EBus; + +} // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp new file mode 100644 index 0000000000..3ca3ec990f --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -0,0 +1,54 @@ +/* + * 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 AzToolsFramework::Prefab +{ + PrefabViewportFocusPathHandler::~PrefabViewportFocusPathHandler() + { + // Disconnect from Prefab Focus Notifications + PrefabFocusNotificationBus::Handler::BusDisconnect(); + } + + void PrefabViewportFocusPathHandler::Initialize(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton) + { + // Get reference to the PrefabFocusInterface handler + m_prefabFocusInterface = AZ::Interface::Get(); + if (m_prefabFocusInterface == nullptr) + { + AZ_Assert(false, "Prefab - could not get PrefabFocusInterface on PrefabViewportFocusPathHandler construction."); + return; + } + + // Connect to Prefab Focus Notifications + PrefabFocusNotificationBus::Handler::BusConnect(); + + // Initialize Widgets + m_breadcrumbsWidget = breadcrumbsWidget; + m_backButton = backButton; + + m_backButton->setEnabled(false); + + connect( + m_breadcrumbsWidget, &AzQtComponents::BreadCrumbs::linkClicked, this, + [&](const QString&, int linkIndex) + { + m_prefabFocusInterface->FocusOnPathIndex(linkIndex); + } + ); + } + + void PrefabViewportFocusPathHandler::OnPrefabFocusChanged() + { + // Push new Path + m_breadcrumbsWidget->pushPath(m_prefabFocusInterface->GetPrefabFocusPath().c_str()); + } + +} // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h new file mode 100644 index 0000000000..63e5579c00 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h @@ -0,0 +1,40 @@ +/* + * 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 + +namespace AzToolsFramework::Prefab +{ + class PrefabFocusInterface; + + class PrefabViewportFocusPathHandler + : public PrefabFocusNotificationBus::Handler + , private QObject + { + public: + ~PrefabViewportFocusPathHandler(); + + void Initialize(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton); + + // PrefabFocusNotificationBus... + void OnPrefabFocusChanged() override; + + private: + AzQtComponents::BreadCrumbs* m_breadcrumbsWidget = nullptr; + QToolButton* m_backButton = nullptr; + + PrefabFocusInterface* m_prefabFocusInterface = nullptr; + }; +} // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 88febef8c2..019ae21674 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -635,6 +635,7 @@ set(FILES Prefab/PrefabFocusHandler.h Prefab/PrefabFocusHandler.cpp Prefab/PrefabFocusInterface.h + Prefab/PrefabFocusNotificationBus.h Prefab/PrefabIdTypes.h Prefab/PrefabLoader.h Prefab/PrefabLoader.cpp @@ -733,6 +734,8 @@ set(FILES UI/Prefab/PrefabIntegrationInterface.h UI/Prefab/PrefabUiHandler.h UI/Prefab/PrefabUiHandler.cpp + UI/Prefab/PrefabViewportFocusPathHandler.h + UI/Prefab/PrefabViewportFocusPathHandler.cpp PythonTerminal/ScriptHelpDialog.cpp PythonTerminal/ScriptHelpDialog.h PythonTerminal/ScriptHelpDialog.ui From 59d7cd60583a782a50b564cc4ed436e21b992247 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 21 Sep 2021 15:01:16 -0700 Subject: [PATCH 041/115] Enable back button and introduce behavior Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Prefab/PrefabFocusHandler.cpp | 5 +++++ .../Prefab/PrefabFocusHandler.h | 1 + .../Prefab/PrefabFocusInterface.h | 8 +++++--- .../Prefab/PrefabViewportFocusPathHandler.cpp | 19 ++++++++++++++++++- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 276d76f848..f203d70e06 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -127,6 +127,11 @@ namespace AzToolsFramework::Prefab return m_instanceFocusPath; } + const int PrefabFocusHandler::GetPrefabFocusPathLength() + { + return m_instanceFocusVector.size(); + } + void PrefabFocusHandler::OnEntityStreamLoadSuccess() { // Focus on the root prefab (AZ::EntityId() will default to it) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index 35ef9aba61..6e8e3ab3e8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -37,6 +37,7 @@ namespace AzToolsFramework::Prefab InstanceOptionalReference GetFocusedPrefabInstance() override; bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) override; const AZ::IO::Path& GetPrefabFocusPath() override; + const int GetPrefabFocusPathLength() override; // EditorEntityContextNotificationBus... void OnEntityStreamLoadSuccess() override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h index 9f695f2bf7..0084a2ef2e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h @@ -43,10 +43,12 @@ namespace AzToolsFramework::Prefab //! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise. virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) = 0; - //! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants. - //! @param entityId The entityId of the queried entity. - //! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise. + //! Returns the path from the root instance to the currently focused instance. + //! @return A path composed from the names of the container entities for the instance path. virtual const AZ::IO::Path& GetPrefabFocusPath() = 0; + + //! Returns the size of the path to the currently focused instance. + virtual const int GetPrefabFocusPathLength() = 0; }; } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index 3ca3ec990f..dba5090170 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -34,8 +34,9 @@ namespace AzToolsFramework::Prefab m_breadcrumbsWidget = breadcrumbsWidget; m_backButton = backButton; - m_backButton->setEnabled(false); + m_backButton->setVisible(false); + // If a part of the path is clicked, focus on that instance connect( m_breadcrumbsWidget, &AzQtComponents::BreadCrumbs::linkClicked, this, [&](const QString&, int linkIndex) @@ -43,12 +44,28 @@ namespace AzToolsFramework::Prefab m_prefabFocusInterface->FocusOnPathIndex(linkIndex); } ); + + // The back button will allow user to go one level up + connect(m_backButton, &QToolButton::clicked, this, + [&]() + { + int length = m_prefabFocusInterface->GetPrefabFocusPathLength(); + + if (length > 1) + { + m_prefabFocusInterface->FocusOnPathIndex(length - 2); + } + } + ); } void PrefabViewportFocusPathHandler::OnPrefabFocusChanged() { // Push new Path m_breadcrumbsWidget->pushPath(m_prefabFocusInterface->GetPrefabFocusPath().c_str()); + + // Only show the back icon button if the path has more than one element + m_backButton->setVisible(m_prefabFocusInterface->GetPrefabFocusPathLength() > 1); } } // namespace AzToolsFramework::Prefab From e2c4dbe2772de00112831e06effaf94e08352f50 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 21 Sep 2021 15:02:02 -0700 Subject: [PATCH 042/115] Fix warning for numeric cast. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzToolsFramework/Prefab/PrefabFocusHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index f203d70e06..a8b8712510 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -129,7 +129,7 @@ namespace AzToolsFramework::Prefab const int PrefabFocusHandler::GetPrefabFocusPathLength() { - return m_instanceFocusVector.size(); + return aznumeric_cast(m_instanceFocusVector.size()); } void PrefabFocusHandler::OnEntityStreamLoadSuccess() From 7a0be4ff6538c9bdbd380d905d0ad5678b9b0d5b Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 21 Sep 2021 17:09:31 -0700 Subject: [PATCH 043/115] Refresh delegate painting in the Outliner even if the widget is not in focus. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../FocusMode/FocusModeNotificationBus.h | 27 +++++++++++++++++++ .../FocusMode/FocusModeSystemComponent.cpp | 7 +++++ .../UI/Outliner/EntityOutlinerTreeView.cpp | 9 +++++++ .../UI/Outliner/EntityOutlinerTreeView.hxx | 5 ++++ .../Prefab/PrefabViewportFocusPathHandler.cpp | 14 ++++++---- .../aztoolsframework_files.cmake | 1 + 6 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h new file mode 100644 index 0000000000..e42c02fe3b --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h @@ -0,0 +1,27 @@ +/* + * 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 + +namespace AzToolsFramework +{ + class FocusModeNotifications + : public AZ::EBusTraits + { + public: + virtual ~FocusModeNotifications() = default; + + virtual void OnEditorFocusChanged(AZ::EntityId entityId) = 0; + }; + + using FocusModeNotificationBus = AZ::EBus; + +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp index e08191032d..817006413d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp @@ -9,6 +9,7 @@ #include #include +#include #include namespace AzToolsFramework @@ -64,7 +65,13 @@ namespace AzToolsFramework void FocusModeSystemComponent::SetFocusRoot(AZ::EntityId entityId) { + if (m_focusRoot == entityId) + { + return; + } + m_focusRoot = entityId; + FocusModeNotificationBus::Broadcast(&FocusModeNotifications::OnEditorFocusChanged, m_focusRoot); // TODO - If m_focusRoot != AZ::EntityId(), activate focus mode via ViewportEditorModeTrackerInterface; else, deactivate focus mode } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp index 0549c600d3..73276973bb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp @@ -38,10 +38,14 @@ namespace AzToolsFramework AZ_Assert((m_editorEntityFrameworkInterface != nullptr), "EntityOutlinerTreeView requires a EditorEntityFrameworkInterface instance on Construction."); + + FocusModeNotificationBus::Handler::BusConnect(); } EntityOutlinerTreeView::~EntityOutlinerTreeView() { + FocusModeNotificationBus::Handler::BusDisconnect(); + ClearQueuedMouseEvent(); } @@ -261,6 +265,11 @@ namespace AzToolsFramework StyledTreeView::StartCustomDrag(indexListSorted, supportedActions); } + + void EntityOutlinerTreeView::OnEditorFocusChanged([[maybe_unused]] AZ::EntityId entityId) + { + viewport()->repaint(); + } } #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx index 66cd082407..8d71b3ed31 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx @@ -15,6 +15,7 @@ #include #include +#include #include #endif @@ -35,6 +36,7 @@ namespace AzToolsFramework //! of other entities. If the selection updates instantly, this would never be possible. class EntityOutlinerTreeView : public AzQtComponents::StyledTreeView + , private FocusModeNotificationBus::Handler { Q_OBJECT; public: @@ -60,6 +62,9 @@ namespace AzToolsFramework void dragMoveEvent(QDragMoveEvent* event) override; void dropEvent(QDropEvent* event) override; + // FocusModeNotificationBus overrides ... + void OnEditorFocusChanged(AZ::EntityId entityId) override; + //! Renders the left side of the item: appropriate background, branch lines, icons. void drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index dba5090170..2c5bc361ea 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -34,11 +34,8 @@ namespace AzToolsFramework::Prefab m_breadcrumbsWidget = breadcrumbsWidget; m_backButton = backButton; - m_backButton->setVisible(false); - // If a part of the path is clicked, focus on that instance - connect( - m_breadcrumbsWidget, &AzQtComponents::BreadCrumbs::linkClicked, this, + connect(m_breadcrumbsWidget, &AzQtComponents::BreadCrumbs::linkClicked, this, [&](const QString&, int linkIndex) { m_prefabFocusInterface->FocusOnPathIndex(linkIndex); @@ -65,7 +62,14 @@ namespace AzToolsFramework::Prefab m_breadcrumbsWidget->pushPath(m_prefabFocusInterface->GetPrefabFocusPath().c_str()); // Only show the back icon button if the path has more than one element - m_backButton->setVisible(m_prefabFocusInterface->GetPrefabFocusPathLength() > 1); + if(m_prefabFocusInterface->GetPrefabFocusPathLength() > 1) + { + m_backButton->show(); + } + else + { + m_backButton->hide(); + } } } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 019ae21674..459198c3ec 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -150,6 +150,7 @@ set(FILES Fingerprinting/TypeFingerprinter.h Fingerprinting/TypeFingerprinter.cpp FocusMode/FocusModeInterface.h + FocusMode/FocusModeNotificationBus.h FocusMode/FocusModeSystemComponent.h FocusMode/FocusModeSystemComponent.cpp Logger/TraceLogger.cpp From 55e2684471d6dd98722bf50bb363974e62b63ab7 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 22 Sep 2021 14:13:50 -0700 Subject: [PATCH 044/115] Refactor Prefab Focus function to move reused code to helper. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Prefab/PrefabFocusHandler.cpp | 37 +++++++++---------- .../Prefab/PrefabFocusHandler.h | 1 + 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index a8b8712510..e2f5660bb7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -56,23 +56,7 @@ namespace AzToolsFramework::Prefab focusedInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId); } - if (!focusedInstance.has_value()) - { - return AZ::Failure(AZStd::string("Prefab Focus Handler: Couldn't find owning instance of entityId provided.")); - } - - if (&m_focusedInstance->get() != &focusedInstance->get()) - { - m_focusedInstance = focusedInstance; - m_focusedTemplateId = focusedInstance->get().GetTemplateId(); - s_focusModeInterface->SetFocusRoot(focusedInstance->get().GetContainerEntityId()); - - RefreshInstanceFocusList(); - - PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); - } - - return AZ::Success(); + return FocusOnPrefabInstance(focusedInstance); } PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex(int index) @@ -82,8 +66,22 @@ namespace AzToolsFramework::Prefab return AZ::Failure(AZStd::string("Prefab Focus Handler: Invalid index on FocusOnPathIndex.")); } - m_focusedInstance = focusedInstance; - m_focusedTemplateId = focusedInstance->get().GetTemplateId(); + InstanceOptionalReference focusedInstance = m_instanceFocusVector[index]; + + return FocusOnPrefabInstance(focusedInstance); + } + + PrefabFocusOperationResult PrefabFocusHandler::FocusOnPrefabInstance(InstanceOptionalReference focusedInstance) + { + if (!focusedInstance.has_value()) + { + return AZ::Failure(AZStd::string("Prefab Focus Handler: invalid instance to focus on.")); + } + + if (&m_focusedInstance->get() != &focusedInstance->get()) + { + m_focusedInstance = focusedInstance; + m_focusedTemplateId = focusedInstance->get().GetTemplateId(); FocusModeInterface* focusModeInterface = AZ::Interface::Get(); if (focusModeInterface) @@ -97,7 +95,6 @@ namespace AzToolsFramework::Prefab } return AZ::Success(); - } TemplateId PrefabFocusHandler::GetFocusedPrefabTemplateId() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index 6e8e3ab3e8..7dd22eda08 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -43,6 +43,7 @@ namespace AzToolsFramework::Prefab void OnEntityStreamLoadSuccess() override; private: + PrefabFocusOperationResult FocusOnPrefabInstance(InstanceOptionalReference focusedInstance); void RefreshInstanceFocusList(); InstanceOptionalReference m_focusedInstance; From be88be4bb897e86d6f7c20c3981c82de7a4fcfc4 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 22 Sep 2021 16:12:11 -0700 Subject: [PATCH 045/115] Minor fixes to pass AR Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- Code/Editor/ViewportTitleDlg.ui | 171 +++++++++--------- .../Prefab/PrefabFocusHandler.cpp | 17 +- .../Prefab/PrefabViewportFocusPathHandler.cpp | 19 +- .../Prefab/PrefabViewportFocusPathHandler.h | 1 + 4 files changed, 105 insertions(+), 103 deletions(-) diff --git a/Code/Editor/ViewportTitleDlg.ui b/Code/Editor/ViewportTitleDlg.ui index e67f04b68a..9b02876054 100644 --- a/Code/Editor/ViewportTitleDlg.ui +++ b/Code/Editor/ViewportTitleDlg.ui @@ -28,7 +28,7 @@ 29 - + 10 @@ -42,19 +42,18 @@ 0 - - - - :/Breadcrumb/img/UI20/Breadcrumb/arrow_left-default.svg:/Breadcrumb/img/UI20/Breadcrumb/arrow_left-default.svg - - - - Back - - - + + + Up one level + + + + :/Breadcrumb/img/UI20/Breadcrumb/arrow_left-default.svg:/Breadcrumb/img/UI20/Breadcrumb/arrow_left-default.svg + + +
- + 0 @@ -64,70 +63,78 @@ - - - - :/Menu/camera.svg:/Menu/camera.svg - - - - Camera settings - - - - - - - Debug information - - - - :/Menu/debug.svg:/Menu/debug.svg - - - - true - - - - - - - Toggle viewport helpers - - - - :/Menu/helpers.svg:/Menu/helpers.svg - - - - true - - - - - - - Viewport resolution - - - - :/Menu/resolution.svg:/Menu/resolution.svg - - - + + + Qt::Horizontal + + + + 40 + 20 + + + - - - Other settings - - - - :/Menu/menu.svg:/Menu/menu.svg - - - + + + Camera settings + + + + :/Menu/camera.svg:/Menu/camera.svg + + + + + + + Debug information + + + + :/Menu/debug.svg:/Menu/debug.svg + + + true + + + + + + + Toggle viewport helpers + + + + :/Menu/helpers.svg:/Menu/helpers.svg + + + true + + + + + + + Viewport resolution + + + + :/Menu/resolution.svg:/Menu/resolution.svg + + + + + + + Other settings + + + + :/Menu/menu.svg:/Menu/menu.svg + + @@ -138,15 +145,9 @@
AzQtComponents/Components/Widgets/Breadcrumbs.h
1 - - AzQtComponents::ButtonDivider - QWidget -
AzQtComponents/Components/ButtonDivider.h
- 1 -
- - - - + + + + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index e2f5660bb7..9ee05425ef 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -83,11 +84,17 @@ namespace AzToolsFramework::Prefab m_focusedInstance = focusedInstance; m_focusedTemplateId = focusedInstance->get().GetTemplateId(); - FocusModeInterface* focusModeInterface = AZ::Interface::Get(); - if (focusModeInterface) - { - focusModeInterface->SetFocusRoot(focusedInstance->get().GetContainerEntityId()); - } + AZ::EntityId containerEntityId = focusedInstance->get().GetContainerEntityId(); + + // Select the container entity + AzToolsFramework::SelectEntity(containerEntityId); + + // Focus on the descendants of the container entity + FocusModeInterface* focusModeInterface = AZ::Interface::Get(); + if (focusModeInterface) + { + focusModeInterface->SetFocusRoot(containerEntityId); + } RefreshInstanceFocusList(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index 2c5bc361ea..c83c0016be 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -11,6 +11,12 @@ namespace AzToolsFramework::Prefab { + PrefabViewportFocusPathHandler::PrefabViewportFocusPathHandler() + { + // Connect to Prefab Focus Notifications + PrefabFocusNotificationBus::Handler::BusConnect(); + } + PrefabViewportFocusPathHandler::~PrefabViewportFocusPathHandler() { // Disconnect from Prefab Focus Notifications @@ -27,9 +33,6 @@ namespace AzToolsFramework::Prefab return; } - // Connect to Prefab Focus Notifications - PrefabFocusNotificationBus::Handler::BusConnect(); - // Initialize Widgets m_breadcrumbsWidget = breadcrumbsWidget; m_backButton = backButton; @@ -60,16 +63,6 @@ namespace AzToolsFramework::Prefab { // Push new Path m_breadcrumbsWidget->pushPath(m_prefabFocusInterface->GetPrefabFocusPath().c_str()); - - // Only show the back icon button if the path has more than one element - if(m_prefabFocusInterface->GetPrefabFocusPathLength() > 1) - { - m_backButton->show(); - } - else - { - m_backButton->hide(); - } } } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h index 63e5579c00..c874c7249f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h @@ -24,6 +24,7 @@ namespace AzToolsFramework::Prefab , private QObject { public: + PrefabViewportFocusPathHandler(); ~PrefabViewportFocusPathHandler(); void Initialize(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton); From 09ce73aa44303cfd4622c578f311bc41c6fef65b Mon Sep 17 00:00:00 2001 From: sweeneys Date: Wed, 22 Sep 2021 17:50:12 -0700 Subject: [PATCH 046/115] Initial update for this module's unit tests on Linux Signed-off-by: sweeneys --- Tools/LyTestTools/ly_test_tools/__init__.py | 17 +- .../_internal/managers/platforms/linux.py | 78 ++++++ .../ly_test_tools/builtin/helpers.py | 7 +- .../environment/process_utils.py | 10 +- .../ly_test_tools/environment/reg_cleaner.py | 4 +- .../ly_test_tools/environment/watchdog.py | 16 +- .../ly_test_tools/launchers/__init__.py | 4 +- .../launchers/platforms/linux/__init__.py | 6 + .../launchers/platforms/linux/launcher.py | 224 ++++++++++++++++++ .../tests/unit/test_builtin_helpers.py | 23 +- .../tests/unit/test_file_system.py | 28 --- .../tests/unit/test_launcher_base.py | 11 +- .../tests/unit/test_launcher_linux.py | 63 +++++ .../tests/unit/test_process_utils.py | 2 +- 14 files changed, 417 insertions(+), 76 deletions(-) create mode 100644 Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py create mode 100644 Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/__init__.py create mode 100644 Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py create mode 100644 Tools/LyTestTools/tests/unit/test_launcher_linux.py diff --git a/Tools/LyTestTools/ly_test_tools/__init__.py b/Tools/LyTestTools/ly_test_tools/__init__.py index 3fb84e9fe5..58340342ab 100755 --- a/Tools/LyTestTools/ly_test_tools/__init__.py +++ b/Tools/LyTestTools/ly_test_tools/__init__.py @@ -11,16 +11,16 @@ import sys logger = logging.getLogger(__name__) -# Supported platforms. +# Supported platforms ALL_PLATFORM_OPTIONS = ['android', 'ios', 'linux', 'mac', 'windows'] -ALL_LAUNCHER_OPTIONS = ['android', 'base', 'mac', 'windows', 'windows_editor', 'windows_dedicated', 'windows_generic'] +ALL_LAUNCHER_OPTIONS = ['android', 'base', 'linux', 'mac', 'windows', 'windows_editor', 'windows_dedicated', 'windows_generic'] ANDROID = False IOS = False # Not implemented - see SPEC-2505 LINUX = sys.platform.startswith('linux') # Not implemented - see SPEC-2501 MAC = sys.platform.startswith('darwin') WINDOWS = sys.platform.startswith('win') -# Detect platforms. +# Detect available platforms HOST_OS_PLATFORM = 'unknown' HOST_OS_EDITOR = 'unknown' HOST_OS_DEDICATED_SERVER = 'unknown' @@ -51,9 +51,12 @@ elif MAC: from ly_test_tools.launchers import MacLauncher LAUNCHERS['mac'] = MacLauncher elif LINUX: - logger.warning(f'Linux operating system is currently not supported, LyTestTools only supports Windows and Mac.') HOST_OS_PLATFORM = 'linux' - HOST_OS_EDITOR = NotImplementedError('LyTestTools does not yet support Linux editor') - HOST_OS_DEDICATED_SERVER = NotImplementedError('LyTestTools does not yet support Linux dedicated server') + HOST_OS_EDITOR = 'linux_editor' + HOST_OS_DEDICATED_SERVER = 'linux_dedicated' + from ly_test_tools.launchers.platforms.linux.launcher import (LinuxLauncher, LinuxEditor, DedicatedLinuxLauncher) + LAUNCHERS['linux'] = LinuxLauncher + LAUNCHERS['linux_editor'] = LinuxEditor + LAUNCHERS['linux_dedicated'] = DedicatedLinuxLauncher else: - logger.warning(f'WARNING: LyTestTools only supports Windows and Mac, got HOST_OS_PLATFORM: "{HOST_OS_PLATFORM}".') + logger.warning(f'WARNING: LyTestTools only supports Windows, Mac, and Linux. Unexpectedly detected HOST_OS_PLATFORM: "{HOST_OS_PLATFORM}".') diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py new file mode 100644 index 0000000000..0cf213c746 --- /dev/null +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py @@ -0,0 +1,78 @@ +""" +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 + +Linux directory and workspace mappings +""" + +import os +import logging + +from ly_test_tools._internal.managers.workspace import AbstractWorkspaceManager +from ly_test_tools._internal.managers.abstract_resource_locator import AbstractResourceLocator + +logger = logging.getLogger(__name__) + +CACHE_DIR = 'linux' +CONFIG_FILE = 'system_linux_pc.cfg' + + +class _LinuxResourceManager(AbstractResourceLocator): + """ + Override for locating resources in a Linux operating system running LyTestTools. + """ + def __init__(self, build_directory: str, project: str): + pass + + def platform_config_file(self): + """ + :return: path to the platform config file + """ + return os.path.join(self.engine_root(), CONFIG_FILE) + + def platform_cache(self): + """ + :return: path to cache for the Linux operating system + """ + return os.path.join(self.project_cache(), CACHE_DIR) + + def project_log(self): + """ + :return: path to 'log' dir in the platform cache dir + """ + return os.path.join(self.project(), 'user', 'log') + + def project_screenshots(self): + """ + :return: path to 'screenshot' dir in the platform cache dir + """ + return os.path.join(self.project(), 'user', 'ScreenShots') + + def editor_log(self): + """ + :return: path to editor.log + """ + return os.path.join(self.project_log(), "editor.log") + + +class LinuxWorkspaceManager(AbstractWorkspaceManager): + """ + A Mac host WorkspaceManager. Contains Mac overridden functions for the AbstractWorkspaceManager class. + Also creates a Mac host ResourceLocator for directory and build mappings. + """ + def __init__( + self, + build_directory=None, + project=None, + tmp_path=None, + output_path=None, + ): + # Type: (str,str,str,str) -> None + super(LinuxWorkspaceManager, self).__init__( + _LinuxResourceManager(build_directory, project), + project=project, + tmp_path=tmp_path, + output_path=output_path, + ) diff --git a/Tools/LyTestTools/ly_test_tools/builtin/helpers.py b/Tools/LyTestTools/ly_test_tools/builtin/helpers.py index f40c8c2234..59117a42f9 100755 --- a/Tools/LyTestTools/ly_test_tools/builtin/helpers.py +++ b/Tools/LyTestTools/ly_test_tools/builtin/helpers.py @@ -9,7 +9,7 @@ Helper file for assisting in building workspaces and setting up LTT with the cur import ly_test_tools._internal.pytest_plugin as pytest_plugin import ly_test_tools._internal.managers.workspace as internal_workspace -from ly_test_tools import MAC, WINDOWS +from ly_test_tools import LINUX, MAC, WINDOWS import os, stat @@ -47,6 +47,11 @@ def create_builtin_workspace( elif MAC: from ly_test_tools._internal.managers.platforms.mac import MacWorkspaceManager build_class = MacWorkspaceManager + elif LINUX: + from ly_test_tools._internal.managers.platforms.linux import LinuxWorkspaceManager + build_class = LinuxWorkspaceManager + else: + raise NotImplementedError("No workspace manager found for current Operating System") instance = build_class( build_directory=build_directory, diff --git a/Tools/LyTestTools/ly_test_tools/environment/process_utils.py b/Tools/LyTestTools/ly_test_tools/environment/process_utils.py index be2f279512..1c0be299a8 100755 --- a/Tools/LyTestTools/ly_test_tools/environment/process_utils.py +++ b/Tools/LyTestTools/ly_test_tools/environment/process_utils.py @@ -12,8 +12,8 @@ import psutil import subprocess import ctypes +import ly_test_tools import ly_test_tools.environment.waiter as waiter -from ly_test_tools import WINDOWS, MAC logger = logging.getLogger(__name__) _PROCESS_OUTPUT_ENCODING = 'utf-8' @@ -182,7 +182,7 @@ def process_is_unresponsive(name): :param name: the name of the process to check :return: True if the specified process is unresponsive and False otherwise """ - if WINDOWS: + if ly_test_tools.WINDOWS: output = check_output(['tasklist', '/FI', f'IMAGENAME eq {name}', '/FI', 'STATUS eq NOT RESPONDING']) @@ -194,7 +194,7 @@ def process_is_unresponsive(name): return True logger.debug(f"Process '{name}' was not unresponsive.") return False - elif MAC: + else: cmd = ["ps", "-axc", "-o", "command,state"] output = check_output(cmd) for line in output.splitlines()[1:]: @@ -209,8 +209,6 @@ def process_is_unresponsive(name): return True logger.debug(f"Process '{name}' was not unresponsive.") return False - else: - raise NotImplementedError('Only Windows and Mac hosts are supported.') def check_output(command, **kwargs): @@ -406,7 +404,7 @@ def close_windows_process(pid, timeout=20, raise_on_missing=False): :param pid: the pid of the process to kill :param raise_on_missing: if set to True, raise RuntimeError if the process does not already exist """ - if not WINDOWS: + if not ly_test_tools.WINDOWS: raise NotImplementedError("close_windows_process() is only implemented on Windows.") if pid is None: diff --git a/Tools/LyTestTools/ly_test_tools/environment/reg_cleaner.py b/Tools/LyTestTools/ly_test_tools/environment/reg_cleaner.py index a3dee1319f..1ffd5a1b4c 100755 --- a/Tools/LyTestTools/ly_test_tools/environment/reg_cleaner.py +++ b/Tools/LyTestTools/ly_test_tools/environment/reg_cleaner.py @@ -8,8 +8,10 @@ Reg cleaner: tools for working with the lumberyard windows registry keys """ import logging import os -import winreg +import ly_test_tools +if ly_test_tools.WINDOWS: + import winreg # OS-specific module availability, must be mocked if this file is accessed elsewhere e.g. unit tests import ly_test_tools.environment.process_utils as process_utils CONST_LY_REG = r'SOFTWARE\O3DE\O3DE' diff --git a/Tools/LyTestTools/ly_test_tools/environment/watchdog.py b/Tools/LyTestTools/ly_test_tools/environment/watchdog.py index 58ac87d9e7..6186a3d354 100755 --- a/Tools/LyTestTools/ly_test_tools/environment/watchdog.py +++ b/Tools/LyTestTools/ly_test_tools/environment/watchdog.py @@ -14,8 +14,8 @@ import re import psutil import time +import ly_test_tools import ly_test_tools.environment.process_utils as process_utils -from ly_test_tools import WINDOWS logger = logging.getLogger(__name__) @@ -28,7 +28,7 @@ class Watchdog(object): DEFAULT_JOIN_TIMEOUT = 10 # seconds def __init__(self, bool_fn, interval=1, raise_on_condition=True, name='ly_test_watchdog', error_message=''): - # type: (func, int, bool, str, str) -> Watchdog + # type: (function, int, bool, str, str) -> Watchdog """ A Watchdog object that takes in a boolean function. It spawns a thread that loops over the boolean function until it returns True. If the boolean function returns True, then a flag will be set and an exception @@ -44,7 +44,7 @@ class Watchdog(object): """ self.caught_failure = False self.name = name - + self._bool_fn = bool_fn self._interval = interval self._raise_on_condition = raise_on_condition @@ -66,7 +66,7 @@ class Watchdog(object): self.caught_failure = False def stop(self, join_timeout=DEFAULT_JOIN_TIMEOUT): - # type: () -> None + # type: (int) -> None """ Stops the watchdog's thread if it's executing by enabling its shutdown Event. If the target function's condition was found, then it will either raise an exception or log an error message. @@ -106,7 +106,7 @@ class Watchdog(object): """ The main function of the watchdog thread. It will repeatedly call its target function until the target function returns True, in which it will set the self.caught_failure attribute to True. - + :return: None """ while True: @@ -128,7 +128,7 @@ class ProcessUnresponsiveWatchdog(Watchdog): Watches a process ID and reports if it is unresponsive for a given timeout. If multiple processes need to be watched, then multiple watchdogs should be instantiated. Note: This is for windows OS only. - + :param process_id: The process id to watch :param interval: The interval (in seconds) for how frequently the bool_fn is called on the thread. :param raise_on_condition: If True, raises an exception when bool_fn returns True. If False, logs an error @@ -138,8 +138,8 @@ class ProcessUnresponsiveWatchdog(Watchdog): :param unresponsive_timeout_seconds: How long the process needs to be unresponsive for in order for the watchdog to report (in seconds). """ - if not WINDOWS: - raise (NotImplementedError, "Process watchdog is only implemented on Windows.") + if not ly_test_tools.WINDOWS: + pass # TODO add non-windows support self._unresponsive_timeout = unresponsive_timeout_seconds self._calculated_timeout_point = None self._pid = process_id diff --git a/Tools/LyTestTools/ly_test_tools/launchers/__init__.py b/Tools/LyTestTools/ly_test_tools/launchers/__init__.py index bb299d89f9..94b712bade 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/__init__.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/__init__.py @@ -6,7 +6,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT """ from ly_test_tools.launchers.platforms.base import Launcher +from ly_test_tools.launchers.platforms.linux.launcher import LinuxLauncher, LinuxEditor, DedicatedLinuxLauncher from ly_test_tools.launchers.platforms.mac.launcher import MacLauncher -from ly_test_tools.launchers.platforms.win.launcher import ( - WinLauncher, DedicatedWinLauncher, WinEditor, WinGenericLauncher) +from ly_test_tools.launchers.platforms.win.launcher import WinLauncher, DedicatedWinLauncher, WinEditor, WinGenericLauncher from ly_test_tools.launchers.platforms.android.launcher import AndroidLauncher diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/__init__.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/__init__.py new file mode 100644 index 0000000000..f5193b300e --- /dev/null +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/__init__.py @@ -0,0 +1,6 @@ +""" +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/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py new file mode 100644 index 0000000000..47a538d90e --- /dev/null +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py @@ -0,0 +1,224 @@ +""" +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 + +Linux compatible launcher +""" + +import logging +import os +import subprocess + +import ly_test_tools.environment.waiter +import ly_test_tools.launchers.exceptions + +from ly_test_tools.launchers.platforms.base import Launcher +from ly_test_tools.launchers.exceptions import TeardownError, ProcessNotStartedError +from tempfile import TemporaryFile + +log = logging.getLogger(__name__) + + +class LinuxLauncher(Launcher): + def __init__(self, build, args): + super(LinuxLauncher, self).__init__(build, args) + self._proc = None + self._ret_code = None + self._tmpout = None + log.debug("Initialized Linux Launcher") + + def binary_path(self): + """ + Return full path to the launcher for this build's configuration and project + + :return: full path to .GameLauncher + """ + assert self.workspace.project is not None + return os.path.join(self.workspace.paths.build_directory(), f"{self.workspace.project}.GameLauncher") + + def setup(self, backupFiles=True, launch_ap=True, configure_settings=True): + """ + Perform setup of this launcher, must be called before launching. + Subclasses should call its parent's setup() before calling its own code, unless it changes configuration files + + :param backupFiles: Bool to backup setup files + :param lauch_ap: Bool to lauch the asset processor + :return: None + """ + # Backup + if backupFiles: + self.backup_settings() + + # Base setup defaults to None + if launch_ap is None: + launch_ap = True + + # Modify and re-configure + if configure_settings: + self.configure_settings() + super(LinuxLauncher, self).setup(backupFiles, launch_ap) + + def launch(self): + """ + Launch the executable and track the subprocess + + :return: None + """ + command = [self.binary_path()] + self.args + self._tmpout = TemporaryFile() + self._proc = subprocess.Popen(command, stdout=self._tmpout, stderr=self._tmpout, universal_newlines=True) + log.debug(f"Started Linux Launcher with command: {command}") + + def get_output(self, encoding="utf-8"): + if self._tmpout is None: + raise ProcessNotStartedError("Process must be started before retrieving output") + + self._tmpout.seek(0) + return self._tmpout.read().decode(encoding) + + def teardown(self): + """ + Perform teardown of this launcher, undoing actions taken by calling setup() + Subclasses should call its parent's teardown() after performing its own teardown. + + :return: None + """ + self.restore_settings() + super(LinuxLauncher, self).teardown() + + def kill(self): + """ + This is a hard kill, and then wait to make sure until it actually ended. + + :return: None + """ + if self._proc is not None: + self._proc.kill() + ly_test_tools.environment.waiter.wait_for( + lambda: not self.is_alive(), + exc=ly_test_tools.launchers.exceptions.TeardownError( + f"Unable to terminate active Linux Launcher with process ID {self._proc.pid}") + ) + self._proc = None + self._ret_code = None + log.debug("Linux Launcher terminated successfully") + + def is_alive(self): + """ + Check the process to verify activity. Side effect of setting self.proc to None if it has ended. + + :return: None + """ + if self._proc is None: + return False + else: + if self._proc.poll() is not None: + self._ret_code = self._proc.poll() + self._proc = None + return False + return True + + def get_pid(self): + # type: () -> int or None + """ + Returns the pid of the launcher process if it exists, else it returns None + + :return: process id or None + """ + if self._proc: + return self._proc.pid + return None + + def get_returncode(self): + # type: () -> int or None + """ + Returns the returncode of the launcher process if it exists, else return None. + The returncode attribute is set when the process is terminated. + + :return: The returncode of the launcher's process + """ + if self._proc: + return self._proc.poll() + else: + return self._ret_code + + def check_returncode(self): + # type: () -> None + """ + Checks the returncode of the launcher if it exists. Raises a CrashError if the returncode is non-zero. Returns + None otherwise. This function must be called after exiting the launcher properly and NOT using its provided + teardown(). Provided teardown() will always return a non-zero returncode and should not be checked. + + :return: None + """ + return_code = self.get_returncode() + if return_code != 0: + log.error(f"Launcher exited with non-zero return code: {return_code}") + raise ly_test_tools.launchers.exceptions.CrashError() + return None + + def configure_settings(self): + """ + Configures system level settings and syncs the launcher to the targeted console IP. + + :return: None + """ + # Update settings via the settings registry to avoid modifying the bootstrap.cfg + host_ip = '127.0.0.1' + self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/project_path={self.workspace.paths.project()}"') + self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/remote_ip={host_ip}"') + self.args.append('--regset="/Amazon/AzCore/Bootstrap/wait_for_connect=1"') + self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/allowed_list={host_ip}"') + + self.workspace.settings.modify_platform_setting("r_AssetProcessorShaderCompiler", 1) + self.workspace.settings.modify_platform_setting("r_ShaderCompilerServer", host_ip) + self.workspace.settings.modify_platform_setting("log_RemoteConsoleAllowedAddresses", host_ip) + + +class DedicatedLinuxLauncher(LinuxLauncher): + + def setup(self, backupFiles=True, launch_ap=False): + """ + Perform setup of this launcher, must be called before launching. + Subclasses should call its parent's setup() before calling its own code, unless it changes configuration files + + :param backupFiles: Bool to backup setup files + :param lauch_ap: Bool to lauch the asset processor + :return: None + """ + # Base setup defaults to None + if launch_ap is None: + launch_ap = False + + super(DedicatedLinuxLauncher, self).setup(backupFiles, launch_ap) + + def binary_path(self): + """ + Return full path to the dedicated server launcher for the build directory. + + :return: full path to Launcher_Server + """ + assert self.workspace.project is not None, ( + 'Project cannot be NoneType - please specify a project name string.') + return os.path.join(f"{self.workspace.paths.build_directory()}", + f"{self.workspace.project}.ServerLauncher") + + +class LinuxEditor(LinuxLauncher): + + def __init__(self, build, args): + super(LinuxEditor, self).__init__(build, args) + self.args.append('--regset="/Amazon/Settings/EnableSourceControl=false"') + self.args.append('--regset="/Amazon/AWS/Preferences/AWSAttributionConsentShown=true"') + self.args.append('--regset="/Amazon/AWS/Preferences/AWSAttributionEnabled=false"') + + def binary_path(self): + """ + Return full path to the Editor for this build's configuration and project + + :return: full path to Editor + """ + assert self.workspace.project is not None + return os.path.join(self.workspace.paths.build_directory(), "Editor") diff --git a/Tools/LyTestTools/tests/unit/test_builtin_helpers.py b/Tools/LyTestTools/tests/unit/test_builtin_helpers.py index 9eb8a1703d..1c583632a8 100755 --- a/Tools/LyTestTools/tests/unit/test_builtin_helpers.py +++ b/Tools/LyTestTools/tests/unit/test_builtin_helpers.py @@ -8,7 +8,6 @@ Unit tests for ly_test_tools.builtin.helpers functions. """ import unittest.mock as mock import os - import pytest import ly_test_tools.builtin.helpers @@ -112,10 +111,11 @@ class TestBuiltinHelpers(object): ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root( initial_path='mock_dev_dir') + @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager.teardown') @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager.setup') @mock.patch('ly_test_tools._internal.managers.artifact_manager.NullArtifactManager', mock.MagicMock()) @mock.patch('os.path.exists', mock.MagicMock(return_value=True)) - def test_SetupBuiltinWorkspace_ValidWorkspaceSetup_ReturnsWorkspaceObject(self, mock_setup): + def test_SetupTeardownBuiltinWorkspace_ValidWorkspaceSetup_ReturnsWorkspaceObject(self, mock_setup, mock_teardown): mock_test_name = 'mock_test_name' mock_test_amount = 10 mock_workspace = ly_test_tools.builtin.helpers.create_builtin_workspace( @@ -125,25 +125,16 @@ class TestBuiltinHelpers(object): output_path='mock_output_path', ) - under_test = ly_test_tools.builtin.helpers.setup_builtin_workspace( + setup_test = ly_test_tools.builtin.helpers.setup_builtin_workspace( mock_workspace, mock_test_name, mock_test_amount) - assert under_test == mock_workspace + assert setup_test == mock_workspace assert mock_setup.call_count == 1 mock_workspace.artifact_manager.set_test_name.assert_called_with( test_name=mock_test_name, amount=mock_test_amount) - @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager.teardown') - @mock.patch('os.path.exists', mock.MagicMock(return_value=True)) - def test_TeardownBuiltinWorkspace_ValidWorkspaceSetup_ReturnsWorkspaceObject(self, mock_teardown): - mock_workspace = ly_test_tools.builtin.helpers.create_builtin_workspace( - build_directory='build_directory', - project='mock_project', - tmp_path='mock_tmp_path', - output_path='mock_output_path', - ) + # Teardown not tested separately due to patched MockedAbstractResourceLocator creating a StopIteration error on Linux + teardown_test = ly_test_tools.builtin.helpers.teardown_builtin_workspace(mock_workspace) - under_test = ly_test_tools.builtin.helpers.teardown_builtin_workspace(mock_workspace) - - assert under_test == mock_workspace + assert teardown_test == mock_workspace assert mock_teardown.call_count == 1 diff --git a/Tools/LyTestTools/tests/unit/test_file_system.py b/Tools/LyTestTools/tests/unit/test_file_system.py index 80c7e51f53..53ca5a700e 100755 --- a/Tools/LyTestTools/tests/unit/test_file_system.py +++ b/Tools/LyTestTools/tests/unit/test_file_system.py @@ -208,20 +208,6 @@ class TestUnZip(unittest.TestCase): self.assertEqual(path, expected_path) - @mock.patch('os.path.exists') - @mock.patch('ly_test_tools.environment.file_system.check_free_space') - @mock.patch('os.path.join') - def test_Unzip_ReleaseBuild_JoinCalledWithNoPathNoExtension(self, mock_join, mock_check_free, mock_exists): - - path = '' - self.src_path = r'C:\packages\lumberyard-1.2.0.3-54321-pc-1234.zip' - mock_exists.return_value = self.exists - - with mock.patch(self.decomp_obj_name, self.mock_decomp): - path = self.call_decomp(self.dest_path, self.src_path) - - mock_join.assert_called_once_with(self.dest_path, 'lumberyard-1.2.0.3-54321-pc-1234') - @mock.patch('ly_test_tools.environment.file_system.logger') @mock.patch('os.path.exists') @mock.patch('ly_test_tools.environment.file_system.check_free_space') @@ -375,20 +361,6 @@ class TestUnTgz(unittest.TestCase): self.assertEqual(path, expected_path) - @mock.patch('ly_test_tools.environment.file_system.check_free_space') - @mock.patch('os.path.join') - @mock.patch('os.stat') - def test_Untgz_ReleaseBuild_JoinCalledWithNoPathNoExtension(self, mock_stat, mock_join, mock_check_free): - - mock_stat.return_value = self.src_stat - - path = '' - self.src_path = r'C:\packages\lumberyard-1.2.0.3-54321-pc-1234.zip' - with mock.patch(self.decomp_obj_name, self.mock_decomp): - path = self.call_decomp(self.dest_path, self.src_path) - - mock_join.assert_called_once_with(self.dest_path, 'lumberyard-1.2.0.3-54321-pc-1234') - @mock.patch('ly_test_tools.environment.file_system.logger') @mock.patch('os.path.exists') @mock.patch('ly_test_tools.environment.file_system.check_free_space') diff --git a/Tools/LyTestTools/tests/unit/test_launcher_base.py b/Tools/LyTestTools/tests/unit/test_launcher_base.py index 8d7daaab72..1ab9129a7d 100755 --- a/Tools/LyTestTools/tests/unit/test_launcher_base.py +++ b/Tools/LyTestTools/tests/unit/test_launcher_base.py @@ -204,21 +204,20 @@ class TestLauncherBuilder(object): """ def test_CreateLauncher_DummyWorkspace_DefaultLauncher(self): dummy_workspace = mock.MagicMock() - launcher_platform = 'windows' under_test = ly_test_tools.launchers.launcher_helper.create_launcher( - dummy_workspace, launcher_platform) + dummy_workspace, ly_test_tools.HOST_OS_EDITOR) assert isinstance(under_test, ly_test_tools.launchers.Launcher) def test_CreateDedicateLauncher_DummyWorkspace_DefaultLauncher(self): dummy_workspace = mock.MagicMock() - launcher_platform = 'windows_dedicated' under_test = ly_test_tools.launchers.launcher_helper.create_dedicated_launcher( - dummy_workspace, launcher_platform) + dummy_workspace, ly_test_tools.HOST_OS_DEDICATED_SERVER) assert isinstance(under_test, ly_test_tools.launchers.Launcher) + @mock.patch('os.path.exists', mock.MagicMock(return_value=True)) def test_CreateEditor_DummyWorkspace_DefaultLauncher(self): dummy_workspace = mock.MagicMock() - launcher_platform = 'windows_editor' + dummy_workspace.paths.build_directory.return_value = 'dummy' under_test = ly_test_tools.launchers.launcher_helper.create_editor( - dummy_workspace, launcher_platform) + dummy_workspace, ly_test_tools.HOST_OS_GENERIC_EXECUTABLE) assert isinstance(under_test, ly_test_tools.launchers.Launcher) diff --git a/Tools/LyTestTools/tests/unit/test_launcher_linux.py b/Tools/LyTestTools/tests/unit/test_launcher_linux.py new file mode 100644 index 0000000000..2a6c6f7014 --- /dev/null +++ b/Tools/LyTestTools/tests/unit/test_launcher_linux.py @@ -0,0 +1,63 @@ +""" +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 + +Unit Tests for linux launcher-wrappers: all are sanity code-path tests, since no interprocess actions should be taken +""" +import os +import pytest +import unittest.mock as mock + +import ly_test_tools.launchers + +pytestmark = pytest.mark.SUITE_smoke + + +class TestLinuxLauncher(object): + + def test_Construct_TestDoubles_LinuxLauncherCreated(self): + under_test = ly_test_tools.launchers.LinuxLauncher(mock.MagicMock(), ["some_args"]) + assert isinstance(under_test, ly_test_tools.launchers.Launcher) + assert isinstance(under_test, ly_test_tools.launchers.LinuxLauncher) + + def test_BinaryPath_DummyPath_AddPathToApp(self): + dummy_path = "dummy_workspace_path" + dummy_project = "dummy_project" + mock_workspace = mock.MagicMock() + mock_workspace.paths.build_directory.return_value = dummy_path + mock_workspace.project = dummy_project + launcher = ly_test_tools.launchers.LinuxLauncher(mock_workspace, ["some_args"]) + + under_test = launcher.binary_path() + expected = os.path.join(dummy_path, f"{dummy_project}.GameLauncher") + + assert under_test == expected + + @mock.patch('ly_test_tools.launchers.LinuxLauncher.binary_path', mock.MagicMock) + @mock.patch('subprocess.Popen') + def test_Launch_DummyArgs_ArgsPassedToPopen(self, mock_subprocess): + dummy_args = ["some_args"] + launcher = ly_test_tools.launchers.LinuxLauncher(mock.MagicMock(), dummy_args) + + launcher.launch() + + mock_subprocess.assert_called_once() + name, args, kwargs = mock_subprocess.mock_calls[0] + unpacked_args = args[0] # args is a list inside a tuple + assert len(dummy_args) > 0, "accidentally removed dummy_args" + for expected_arg in dummy_args: + assert expected_arg in unpacked_args + + @mock.patch('ly_test_tools.launchers.LinuxLauncher.is_alive') + def test_Kill_MockAliveFalse_SilentSuccess(self, mock_alive): + mock_alive.return_value = False + mock_proc = mock.MagicMock() + launcher = ly_test_tools.launchers.LinuxLauncher(mock.MagicMock(), ["dummy"]) + launcher._proc = mock_proc + + launcher.kill() + + mock_proc.kill.assert_called_once() + mock_alive.assert_called_once() diff --git a/Tools/LyTestTools/tests/unit/test_process_utils.py b/Tools/LyTestTools/tests/unit/test_process_utils.py index a3cdae84ad..de40fb8e34 100755 --- a/Tools/LyTestTools/tests/unit/test_process_utils.py +++ b/Tools/LyTestTools/tests/unit/test_process_utils.py @@ -191,7 +191,7 @@ class TestSubprocessCheckCallWrapperSafe(unittest.TestCase): reason="tests.unit.test_process_utils is restricted to the Windows platform.") class TestCloseWindowsProcess(unittest.TestCase): - @mock.patch('ly_test_tools.environment.process_utils.WINDOWS', False) + @mock.patch('ly_test_tools.WINDOWS', False) def test_CloseWindowsProccess_NotOnWindows_Error(self): with pytest.raises(NotImplementedError): process_utils.close_windows_process(1) From ebcf3723f9587ff2260d8c8d5ab63289decb2416 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 23 Sep 2021 22:58:39 -0500 Subject: [PATCH 047/115] Material Component: Can set material property overrides on default materials No longer need to assign material overrides to set/edit properties in UI or script Material component will load and use the default material for a slot if no override is assigned Signed-off-by: Guthrie Adams --- .../Feature/Material/MaterialAssignment.h | 8 ++ .../Source/Material/MaterialAssignment.cpp | 44 +++++++- .../Viewport/MaterialViewportRenderer.cpp | 8 +- .../Material/MaterialComponentBus.h | 3 + .../EditorMaterialComponentInspector.cpp | 17 ++- .../Material/EditorMaterialComponentSlot.cpp | 20 ++-- .../Material/EditorMaterialComponentSlot.h | 1 + .../Material/MaterialComponentController.cpp | 103 +++++++++++++----- .../Material/MaterialComponentController.h | 4 + 9 files changed, 162 insertions(+), 46 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index 987e78ae0f..797bd5ee98 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -39,13 +39,21 @@ namespace AZ //! Otherwise an attempt will be made to find or create a shared instance. void RebuildInstance(); + //! Release asset and instance references + void Release(); + + //! Return true if contained assets have not been loaded + bool RequiresLoading() const; + //! Returns a string composed of the asset path. AZStd::string ToString() const; Data::Asset m_materialAsset; + Data::Asset m_defaultMaterialAsset; Data::Instance m_materialInstance; MaterialPropertyOverrideMap m_propertyOverrides; RPI::MaterialModelUvOverrideMap m_matModUvOverrides; + bool m_materialInstancePreCreated = false; }; using MaterialAssignmentMap = AZStd::unordered_map; diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index 4d437be244..e70f0f5393 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -69,9 +69,9 @@ namespace AZ } MaterialAssignment::MaterialAssignment(const AZ::Data::AssetId& materialAssetId) - : m_materialInstance() + : m_materialAsset(materialAssetId, AZ::AzTypeInfo::Uuid()) + , m_materialInstance() { - m_materialAsset.Create(materialAssetId); } MaterialAssignment::MaterialAssignment(const Data::Asset& asset) @@ -88,14 +88,50 @@ namespace AZ void MaterialAssignment::RebuildInstance() { - if (m_materialAsset.IsReady()) + if (m_materialInstancePreCreated) + { + return; + } + + if (m_materialAsset.GetId().IsValid()) + { + if (m_materialAsset.IsReady()) + { + m_materialInstance = + m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); + AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); + } + return; + } + + if (m_defaultMaterialAsset.IsReady()) { m_materialInstance = - m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); + m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_defaultMaterialAsset) : RPI::Material::Create(m_defaultMaterialAsset); AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); } } + void MaterialAssignment::Release() + { + if (!m_materialInstancePreCreated) + { + m_materialInstance = nullptr; + } + m_materialAsset.Release(); + m_defaultMaterialAsset.Release(); + } + + bool MaterialAssignment::RequiresLoading() const + { + return + !m_materialInstancePreCreated && + !m_materialAsset.IsReady() && + !m_materialAsset.IsLoading() && + !m_defaultMaterialAsset.IsReady() && + !m_defaultMaterialAsset.IsLoading(); + } + AZStd::string MaterialAssignment::ToString() const { AZStd::string assetPathString; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp index 7edff11174..6d6fd377e3 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp @@ -182,7 +182,9 @@ namespace MaterialEditor AZ_Error("MaterialViewportRenderer", m_shadowCatcherMaterial != nullptr, "Could not create shadow catcher material."); AZ::Render::MaterialAssignmentMap shadowCatcherMaterials; - shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId].m_materialInstance = m_shadowCatcherMaterial; + 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); @@ -291,7 +293,9 @@ namespace MaterialEditor MaterialDocumentRequestBus::EventResult(materialInstance, documentId, &MaterialDocumentRequestBus::Events::GetInstance); AZ::Render::MaterialAssignmentMap materials; - materials[AZ::Render::DefaultMaterialAssignmentId].m_materialInstance = materialInstance; + 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); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h index ace16ba6ca..ed7f1564ac 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h @@ -151,7 +151,9 @@ namespace AZ //! Returns the list of all ModelMaterialSlot's for the model, across all LODs. virtual RPI::ModelMaterialSlotMap GetModelMaterialSlots() const = 0; + //! Returns the available, overridable material slots and the default assigned materials virtual MaterialAssignmentMap GetMaterialAssignments() const = 0; + virtual AZStd::unordered_set GetModelUvNames() const = 0; }; using MaterialReceiverRequestBus = EBus; @@ -161,6 +163,7 @@ namespace AZ : public ComponentBus { public: + //! Notification that overridable material slots are available or have changed virtual void OnMaterialAssignmentsChanged() = 0; }; using MaterialReceiverNotificationBus = EBus; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index a3152faf87..f526abde0c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -88,6 +88,12 @@ namespace AZ AZ::Data::AssetId materialAssetId = {}; MaterialComponentRequestBus::EventResult( materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId); + if (!materialAssetId.IsValid()) + { + MaterialComponentRequestBus::EventResult( + materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, + m_materialAssignmentId); + } if (!materialAssetId.IsValid()) { @@ -728,11 +734,16 @@ namespace AZ void MaterialPropertyInspector::UpdateUI() { - AZ::Data::AssetId assetId; + AZ::Data::AssetId materialAssetId = {}; MaterialComponentRequestBus::EventResult( - assetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId); + materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId); + if (!materialAssetId.IsValid()) + { + MaterialComponentRequestBus::EventResult( + materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_materialAssignmentId); + } - if (IsLoaded() && m_editData.m_materialAssetId == assetId) + if (IsLoaded() && m_editData.m_materialAssetId == materialAssetId) { LoadOverridesFromEntity(); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index 363221d3fc..9ef38c4838 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -117,10 +117,16 @@ namespace AZ } }; + AZ::Data::AssetId EditorMaterialComponentSlot::GetActiveAssetId() const + { + return m_materialAsset.GetId().IsValid() ? m_materialAsset.GetId() : GetDefaultAssetId(); + } + AZ::Data::AssetId EditorMaterialComponentSlot::GetDefaultAssetId() const { AZ::Data::AssetId assetId; - MaterialComponentRequestBus::EventResult(assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id); + MaterialComponentRequestBus::EventResult( + assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id); return assetId; } @@ -134,7 +140,7 @@ namespace AZ bool EditorMaterialComponentSlot::HasSourceData() const { // The slot only has valid source data if the source path is valid and the file has the correct extension - const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId()); + const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(GetActiveAssetId()); return !sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension); } @@ -219,7 +225,7 @@ namespace AZ void EditorMaterialComponentSlot::OpenMaterialEditor() const { - const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId()); + const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(GetActiveAssetId()); if (!sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension)) { EditorMaterialSystemComponentRequestBus::Broadcast( @@ -235,7 +241,7 @@ namespace AZ void EditorMaterialComponentSlot::OpenUvNameMapInspector() { - if (m_materialAsset.GetId().IsValid()) + if (GetActiveAssetId().IsValid()) { AZStd::unordered_set modelUvNames; MaterialReceiverRequestBus::EventResult(modelUvNames, m_entityId, &MaterialReceiverRequestBus::Events::GetModelUvNames); @@ -251,7 +257,7 @@ namespace AZ }; if (EditorMaterialComponentInspector::OpenInspectorDialog( - m_materialAsset.GetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback)) + GetActiveAssetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback)) { OnDataChanged(); } @@ -273,10 +279,10 @@ namespace AZ action->setEnabled(HasSourceData()); action = menu.addAction("Edit Material Instance...", [this]() { OpenMaterialInspector(); }); - action->setEnabled(m_materialAsset.GetId().IsValid()); + action->setEnabled(GetActiveAssetId().IsValid()); action = menu.addAction("Edit Material Instance UV Map...", [this]() { OpenUvNameMapInspector(); }); - action->setEnabled(m_materialAsset.GetId().IsValid()); + action->setEnabled(GetActiveAssetId().IsValid()); menu.addSeparator(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h index 01e357f1bb..377fe9a18b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h @@ -30,6 +30,7 @@ namespace AZ static void Reflect(ReflectContext* context); static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); + AZ::Data::AssetId GetActiveAssetId() const; AZ::Data::AssetId GetDefaultAssetId() const; AZStd::string GetLabel() const; bool HasSourceData() const; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 1d9f1e81dd..69d2ef2460 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -110,12 +110,14 @@ namespace AZ m_queuedMaterialUpdateNotification = false; MaterialComponentRequestBus::Handler::BusConnect(m_entityId); + MaterialReceiverNotificationBus::Handler::BusConnect(m_entityId); LoadMaterials(); } void MaterialComponentController::Deactivate() { MaterialComponentRequestBus::Handler::BusDisconnect(); + MaterialReceiverNotificationBus::Handler::BusDisconnect(); TickBus::Handler::BusDisconnect(); ReleaseMaterials(); @@ -214,13 +216,29 @@ namespace AZ bool anyQueued = false; for (auto& materialPair : m_configuration.m_materials) { - auto& materialAsset = materialPair.second.m_materialAsset; + if (materialPair.second.m_materialInstancePreCreated) + { + continue; + } - if (materialAsset.GetId().IsValid() && !Data::AssetBus::MultiHandler::BusIsConnectedId(materialAsset.GetId())) + if (materialPair.second.m_materialAsset.GetId().IsValid() && + !Data::AssetBus::MultiHandler::BusIsConnectedId(materialPair.second.m_materialAsset.GetId())) { anyQueued = true; - materialAsset.QueueLoad(); - Data::AssetBus::MultiHandler::BusConnect(materialAsset.GetId()); + materialPair.second.m_materialAsset.QueueLoad(); + Data::AssetBus::MultiHandler::BusConnect(materialPair.second.m_materialAsset.GetId()); + continue; + } + + materialPair.second.m_defaultMaterialAsset = AZ::Data::Asset( + GetDefaultMaterialAssetId(materialPair.first), AZ::AzTypeInfo::Uuid()); + + if (materialPair.second.m_defaultMaterialAsset.GetId().IsValid() && + !Data::AssetBus::MultiHandler::BusIsConnectedId(materialPair.second.m_defaultMaterialAsset.GetId())) + { + anyQueued = true; + materialPair.second.m_defaultMaterialAsset.QueueLoad(); + Data::AssetBus::MultiHandler::BusConnect(materialPair.second.m_defaultMaterialAsset.GetId()); } } @@ -236,13 +254,22 @@ namespace AZ for (auto& materialPair : m_configuration.m_materials) { - auto& materialAsset = materialPair.second.m_materialAsset; - if (materialAsset.GetId() == asset.GetId()) + if (materialPair.second.m_materialAsset.GetId() == asset.GetId()) { - materialAsset = asset; + materialPair.second.m_materialAsset = asset; } - if (materialAsset.GetId().IsValid() && !materialAsset.IsReady()) + if (materialPair.second.m_materialAsset.GetId().IsValid() && !materialPair.second.m_materialAsset.IsReady()) + { + allReady = false; + } + + if (materialPair.second.m_defaultMaterialAsset.GetId() == asset.GetId()) + { + materialPair.second.m_defaultMaterialAsset = asset; + } + + if (materialPair.second.m_defaultMaterialAsset.GetId().IsValid() && !materialPair.second.m_defaultMaterialAsset.IsReady()) { allReady = false; } @@ -268,11 +295,7 @@ namespace AZ for (auto& materialPair : m_configuration.m_materials) { - if (materialPair.second.m_materialAsset.GetId().IsValid()) - { - materialPair.second.m_materialAsset.Release(); - materialPair.second.m_materialInstance = nullptr; - } + materialPair.second.Release(); } MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsUpdated, m_configuration.m_materials); @@ -459,18 +482,21 @@ namespace AZ void MaterialComponentController::SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::any& value) { auto& materialAssignment = m_configuration.m_materials[materialAssignmentId]; + const bool wasEmpty = materialAssignment.m_propertyOverrides.empty(); + materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value; - // When applying property overrides for the first time, new instance needs to be created in case the current instance is already used somewhere else to keep overrides local - if (materialAssignment.m_propertyOverrides.empty()) + if (materialAssignment.RequiresLoading()) { - materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value; - materialAssignment.RebuildInstance(); - MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialInstanceCreated, materialAssignment); - QueueMaterialUpdateNotification(); + LoadMaterials(); + return; } - else + + if (wasEmpty != materialAssignment.m_propertyOverrides.empty()) { - materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value; + materialAssignment.RebuildInstance(); + MaterialComponentNotificationBus::Event( + m_entityId, &MaterialComponentNotifications::OnMaterialInstanceCreated, materialAssignment); + QueueMaterialUpdateNotification(); } QueuePropertyChanges(materialAssignmentId); @@ -703,6 +729,12 @@ namespace AZ const bool wasEmpty = materialAssignment.m_propertyOverrides.empty(); materialAssignment.m_propertyOverrides = propertyOverrides; + if (materialAssignment.RequiresLoading()) + { + LoadMaterials(); + return; + } + if (wasEmpty != materialAssignment.m_propertyOverrides.empty()) { materialAssignment.RebuildInstance(); @@ -712,14 +744,11 @@ namespace AZ QueuePropertyChanges(materialAssignmentId); } - MaterialPropertyOverrideMap MaterialComponentController::GetPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) const + MaterialPropertyOverrideMap MaterialComponentController::GetPropertyOverrides( + const MaterialAssignmentId& materialAssignmentId) const { const auto materialIt = m_configuration.m_materials.find(materialAssignmentId); - if (materialIt == m_configuration.m_materials.end()) - { - return {}; - } - return materialIt->second.m_propertyOverrides; + return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_propertyOverrides : MaterialPropertyOverrideMap(); } void MaterialComponentController::SetModelUvOverrides( @@ -729,6 +758,12 @@ namespace AZ const bool wasEmpty = materialAssignment.m_matModUvOverrides.empty(); materialAssignment.m_matModUvOverrides = modelUvOverrides; + if (materialAssignment.RequiresLoading()) + { + LoadMaterials(); + return; + } + if (wasEmpty != materialAssignment.m_matModUvOverrides.empty()) { materialAssignment.RebuildInstance(); @@ -742,11 +777,19 @@ namespace AZ const MaterialAssignmentId& materialAssignmentId) const { const auto materialIt = m_configuration.m_materials.find(materialAssignmentId); - if (materialIt == m_configuration.m_materials.end()) + return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_matModUvOverrides : AZ::RPI::MaterialModelUvOverrideMap(); + } + + void MaterialComponentController::OnMaterialAssignmentsChanged() + { + for (const auto& materialPair : m_configuration.m_materials) { - return {}; + if (materialPair.second.RequiresLoading()) + { + LoadMaterials(); + return; + } } - return materialIt->second.m_matModUvOverrides; } void MaterialComponentController::QueuePropertyChanges(const MaterialAssignmentId& materialAssignmentId) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index 2bf15ca3b8..b9bce4ce72 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -22,6 +22,7 @@ namespace AZ //! to provide material overrides on a per-entity basis. class MaterialComponentController final : MaterialComponentRequestBus::Handler + , MaterialReceiverNotificationBus::Handler , Data::AssetBus::MultiHandler , TickBus::Handler { @@ -100,6 +101,9 @@ namespace AZ const MaterialAssignmentId& materialAssignmentId, const AZ::RPI::MaterialModelUvOverrideMap& modelUvOverrides) override; AZ::RPI::MaterialModelUvOverrideMap GetModelUvOverrides(const MaterialAssignmentId& materialAssignmentId) const override; + //! MaterialReceiverNotificationBus::Handler overrides... + void OnMaterialAssignmentsChanged() override; + private: AZ_DISABLE_COPY(MaterialComponentController); From b0ea4ac38937abef01be2328fbc7eb86a624526b Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 24 Sep 2021 13:03:44 -0500 Subject: [PATCH 048/115] moved code for applying properties to MaterialAssignment added lambdas for queuing and updating assets Signed-off-by: Guthrie Adams --- .../Feature/Material/MaterialAssignment.h | 3 + .../Source/Material/MaterialAssignment.cpp | 29 ++++ .../Material/MaterialComponentController.cpp | 126 +++++++----------- .../Material/MaterialComponentController.h | 2 +- 4 files changed, 78 insertions(+), 82 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index 797bd5ee98..40555bae00 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -45,6 +45,9 @@ namespace AZ //! Return true if contained assets have not been loaded bool RequiresLoading() const; + //! Applies property overrides to material instance + bool ApplyProperties(); + //! Returns a string composed of the asset path. AZStd::string ToString() const; diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index e70f0f5393..56ad6b8b52 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -132,6 +132,35 @@ namespace AZ !m_defaultMaterialAsset.IsLoading(); } + bool MaterialAssignment::ApplyProperties() + { + // if there is no instance or no properties there's nothing to apply + if (!m_materialInstance || m_propertyOverrides.empty()) + { + return true; + } + + if (m_materialInstance->CanCompile()) + { + for (const auto& propertyPair : m_propertyOverrides) + { + if (!propertyPair.second.empty()) + { + const auto& materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyPair.first); + if (!materialPropertyIndex.IsNull()) + { + m_materialInstance->SetPropertyValue( + materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second)); + } + } + } + + return m_materialInstance->Compile(); + } + + return false; + } + AZStd::string MaterialAssignment::ToString() const { AZStd::string assetPathString; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 69d2ef2460..cfb47d74f5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -147,56 +147,26 @@ namespace AZ void MaterialComponentController::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - AZStd::unordered_set propertyOverrides; - AZStd::swap(m_queuedPropertyOverrides, propertyOverrides); + AZStd::unordered_set materialsWithDirtyProperties; + AZStd::swap(m_materialsWithDirtyProperties, materialsWithDirtyProperties); // Iterate through all MaterialAssignmentId's that have property overrides and attempt to apply them // if material instance is already compiling, delay application of property overrides until next frame - for (const auto& materialAssignmentId : propertyOverrides) + for (const auto& materialAssignmentId : materialsWithDirtyProperties) { const auto materialIt = m_configuration.m_materials.find(materialAssignmentId); - if (materialIt == m_configuration.m_materials.end()) + if (materialIt != m_configuration.m_materials.end()) { - //Skip materials that do not exist in the map - continue; - } - - auto materialInstance = materialIt->second.m_materialInstance; - if (!materialInstance) - { - //Skip materials with an invalid instances - continue; - } - - if (!materialInstance->CanCompile()) - { - //If a material cannot currently be compiled then it must be queued again - m_queuedPropertyOverrides.emplace(materialAssignmentId); - continue; - } - - const auto& propertyOverrides2 = materialIt->second.m_propertyOverrides; - for (auto& propertyPair : propertyOverrides2) - { - if (propertyPair.second.empty()) + if (!materialIt->second.ApplyProperties()) { - continue; + // If a material cannot currently be compiled then it must be queued again + m_materialsWithDirtyProperties.emplace(materialAssignmentId); } - - const auto& materialPropertyIndex = materialInstance->FindPropertyIndex(propertyPair.first); - if (materialPropertyIndex.IsNull()) - { - continue; - } - - materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second)); } - - materialInstance->Compile(); } // Only disconnect from tick bus and send notification after all pending properties have been applied - if (m_queuedPropertyOverrides.empty()) + if (m_materialsWithDirtyProperties.empty()) { if (m_queuedMaterialUpdateNotification) { @@ -214,6 +184,18 @@ namespace AZ Data::AssetBus::MultiHandler::BusDisconnect(); bool anyQueued = false; + auto queueAsset = [&anyQueued, this](AZ::Data::Asset& materialAsset) -> bool + { + if (materialAsset.GetId().IsValid() && !this->Data::AssetBus::MultiHandler::BusIsConnectedId(materialAsset.GetId())) + { + anyQueued = true; + materialAsset.QueueLoad(); + this->Data::AssetBus::MultiHandler::BusConnect(materialAsset.GetId()); + return true; + } + return false; + }; + for (auto& materialPair : m_configuration.m_materials) { if (materialPair.second.m_materialInstancePreCreated) @@ -221,24 +203,16 @@ namespace AZ continue; } - if (materialPair.second.m_materialAsset.GetId().IsValid() && - !Data::AssetBus::MultiHandler::BusIsConnectedId(materialPair.second.m_materialAsset.GetId())) + materialPair.second.m_defaultMaterialAsset = {}; + if (!queueAsset(materialPair.second.m_materialAsset)) { - anyQueued = true; - materialPair.second.m_materialAsset.QueueLoad(); - Data::AssetBus::MultiHandler::BusConnect(materialPair.second.m_materialAsset.GetId()); - continue; - } - - materialPair.second.m_defaultMaterialAsset = AZ::Data::Asset( - GetDefaultMaterialAssetId(materialPair.first), AZ::AzTypeInfo::Uuid()); - - if (materialPair.second.m_defaultMaterialAsset.GetId().IsValid() && - !Data::AssetBus::MultiHandler::BusIsConnectedId(materialPair.second.m_defaultMaterialAsset.GetId())) - { - anyQueued = true; - materialPair.second.m_defaultMaterialAsset.QueueLoad(); - Data::AssetBus::MultiHandler::BusConnect(materialPair.second.m_defaultMaterialAsset.GetId()); + // Only assign and load the default material if there was no material override and there are propoerties to apply + if (!materialPair.second.m_propertyOverrides.empty() || !materialPair.second.m_matModUvOverrides.empty()) + { + materialPair.second.m_defaultMaterialAsset = AZ::Data::Asset( + GetDefaultMaterialAssetId(materialPair.first), AZ::AzTypeInfo::Uuid()); + queueAsset(materialPair.second.m_defaultMaterialAsset); + } } } @@ -251,28 +225,23 @@ namespace AZ void MaterialComponentController::InitializeMaterialInstance(const Data::Asset& asset) { bool allReady = true; + auto updateAsset = [&](AZ::Data::Asset& materialAsset) + { + if (materialAsset.GetId() == asset.GetId()) + { + materialAsset = asset; + } + + if (materialAsset.GetId().IsValid() && !materialAsset.IsReady()) + { + allReady = false; + } + }; for (auto& materialPair : m_configuration.m_materials) { - if (materialPair.second.m_materialAsset.GetId() == asset.GetId()) - { - materialPair.second.m_materialAsset = asset; - } - - if (materialPair.second.m_materialAsset.GetId().IsValid() && !materialPair.second.m_materialAsset.IsReady()) - { - allReady = false; - } - - if (materialPair.second.m_defaultMaterialAsset.GetId() == asset.GetId()) - { - materialPair.second.m_defaultMaterialAsset = asset; - } - - if (materialPair.second.m_defaultMaterialAsset.GetId().IsValid() && !materialPair.second.m_defaultMaterialAsset.IsReady()) - { - allReady = false; - } + updateAsset(materialPair.second.m_materialAsset); + updateAsset(materialPair.second.m_defaultMaterialAsset); } if (allReady) @@ -463,12 +432,7 @@ namespace AZ AZ::Data::AssetId MaterialComponentController::GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const { auto materialIt = m_configuration.m_materials.find(materialAssignmentId); - if (materialIt == m_configuration.m_materials.end()) - { - return {}; - } - - return materialIt->second.m_materialAsset.GetId(); + return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_materialAsset.GetId() : AZ::Data::AssetId(); } void MaterialComponentController::ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) @@ -794,7 +758,7 @@ namespace AZ void MaterialComponentController::QueuePropertyChanges(const MaterialAssignmentId& materialAssignmentId) { - m_queuedPropertyOverrides.emplace(materialAssignmentId); + m_materialsWithDirtyProperties.emplace(materialAssignmentId); if (!TickBus::Handler::BusIsConnected()) { TickBus::Handler::BusConnect(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index b9bce4ce72..1594456a31 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -125,7 +125,7 @@ namespace AZ EntityId m_entityId; MaterialComponentConfig m_configuration; - AZStd::unordered_set m_queuedPropertyOverrides; + AZStd::unordered_set m_materialsWithDirtyProperties; bool m_queuedMaterialUpdateNotification = false; }; } // namespace Render From d151e16fc54dc0a043d53fec3ef83b973e4e03ed Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 24 Sep 2021 13:23:15 -0500 Subject: [PATCH 049/115] RebuildInstance only checks Asset::IsReady Signed-off-by: Guthrie Adams --- .../Code/Source/Material/MaterialAssignment.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index 56ad6b8b52..656d990307 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -93,21 +93,14 @@ namespace AZ return; } - if (m_materialAsset.GetId().IsValid()) + if (m_materialAsset.IsReady()) { - if (m_materialAsset.IsReady()) - { - m_materialInstance = - m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); - AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); - } - return; + m_materialInstance = m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); + AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); } - - if (m_defaultMaterialAsset.IsReady()) + else if (m_defaultMaterialAsset.IsReady()) { - m_materialInstance = - m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_defaultMaterialAsset) : RPI::Material::Create(m_defaultMaterialAsset); + m_materialInstance = m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_defaultMaterialAsset) : RPI::Material::Create(m_defaultMaterialAsset); AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); } } From f012407506e2fb508107dfe53c25e5171c1e3c5b Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Fri, 24 Sep 2021 18:49:17 -0700 Subject: [PATCH 050/115] Addressed multiple minor CR comments. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../FocusMode/FocusModeNotificationBus.h | 8 ++++++-- .../Prefab/PrefabFocusHandler.cpp | 15 +++++++-------- .../AzToolsFramework/Prefab/PrefabFocusHandler.h | 14 +++++++------- .../Prefab/PrefabFocusInterface.h | 10 +++++----- .../Prefab/PrefabFocusNotificationBus.h | 11 ++++++++--- .../UI/Prefab/PrefabViewportFocusPathHandler.cpp | 4 +--- .../UI/Prefab/PrefabViewportFocusPathHandler.h | 2 +- 7 files changed, 35 insertions(+), 29 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h index e42c02fe3b..a16bb9a3ef 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h @@ -13,12 +13,16 @@ namespace AzToolsFramework { + //! Used to notify when the editor focus changes. class FocusModeNotifications : public AZ::EBusTraits { - public: - virtual ~FocusModeNotifications() = default; + protected: + ~FocusModeNotifications() = default; + public: + //! Triggered when the editor focus is changed to a different entity. + //! @param entityId The entity the focus has been moved to. virtual void OnEditorFocusChanged(AZ::EntityId entityId) = 0; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 7d4ca36458..6135f35df5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -79,7 +79,7 @@ namespace AzToolsFramework::Prefab return AZ::Failure(AZStd::string("Prefab Focus Handler: invalid instance to focus on.")); } - if (&m_focusedInstance->get() != &focusedInstance->get()) + if (!m_focusedInstance.has_value() || &m_focusedInstance->get() != &focusedInstance->get()) { m_focusedInstance = focusedInstance; m_focusedTemplateId = focusedInstance->get().GetTemplateId(); @@ -90,8 +90,7 @@ namespace AzToolsFramework::Prefab AzToolsFramework::SelectEntity(containerEntityId); // Focus on the descendants of the container entity - FocusModeInterface* focusModeInterface = AZ::Interface::Get(); - if (focusModeInterface) + if (FocusModeInterface* focusModeInterface = AZ::Interface::Get()) { focusModeInterface->SetFocusRoot(containerEntityId); } @@ -104,17 +103,17 @@ namespace AzToolsFramework::Prefab return AZ::Success(); } - TemplateId PrefabFocusHandler::GetFocusedPrefabTemplateId() + TemplateId PrefabFocusHandler::GetFocusedPrefabTemplateId() const { return m_focusedTemplateId; } - InstanceOptionalReference PrefabFocusHandler::GetFocusedPrefabInstance() + InstanceOptionalReference PrefabFocusHandler::GetFocusedPrefabInstance() const { return m_focusedInstance; } - bool PrefabFocusHandler::IsOwningPrefabBeingFocused(AZ::EntityId entityId) + bool PrefabFocusHandler::IsOwningPrefabBeingFocused(AZ::EntityId entityId) const { if (!m_focusedInstance.has_value()) { @@ -132,12 +131,12 @@ namespace AzToolsFramework::Prefab return instance.has_value() && (&instance->get() == &m_focusedInstance->get()); } - const AZ::IO::Path& PrefabFocusHandler::GetPrefabFocusPath() + const AZ::IO::Path& PrefabFocusHandler::GetPrefabFocusPath() const { return m_instanceFocusPath; } - const int PrefabFocusHandler::GetPrefabFocusPathLength() + const int PrefabFocusHandler::GetPrefabFocusPathLength() const { return aznumeric_cast(m_instanceFocusVector.size()); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index 7dd22eda08..0362e2d66d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -30,16 +30,16 @@ namespace AzToolsFramework::Prefab PrefabFocusHandler(); ~PrefabFocusHandler(); - // PrefabFocusInterface override ... + // PrefabFocusInterface overrides ... PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override; PrefabFocusOperationResult FocusOnPathIndex(int index) override; - TemplateId GetFocusedPrefabTemplateId() override; - InstanceOptionalReference GetFocusedPrefabInstance() override; - bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) override; - const AZ::IO::Path& GetPrefabFocusPath() override; - const int GetPrefabFocusPathLength() override; + TemplateId GetFocusedPrefabTemplateId() const override; + InstanceOptionalReference GetFocusedPrefabInstance() const override; + bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const override; + const AZ::IO::Path& GetPrefabFocusPath() const override; + const int GetPrefabFocusPathLength() const override; - // EditorEntityContextNotificationBus... + // EditorEntityContextNotificationBus overrides ... void OnEntityStreamLoadSuccess() override; private: diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h index 0084a2ef2e..3efd2d4deb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h @@ -33,22 +33,22 @@ namespace AzToolsFramework::Prefab virtual PrefabFocusOperationResult FocusOnPathIndex(int index) = 0; //! Returns the template id of the instance the prefab system is focusing on. - virtual TemplateId GetFocusedPrefabTemplateId() = 0; + virtual TemplateId GetFocusedPrefabTemplateId() const = 0; //! Returns a reference to the instance the prefab system is focusing on. - virtual InstanceOptionalReference GetFocusedPrefabInstance() = 0; + virtual InstanceOptionalReference GetFocusedPrefabInstance() const = 0; //! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants. //! @param entityId The entityId of the queried entity. //! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise. - virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) = 0; + virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const = 0; //! Returns the path from the root instance to the currently focused instance. //! @return A path composed from the names of the container entities for the instance path. - virtual const AZ::IO::Path& GetPrefabFocusPath() = 0; + virtual const AZ::IO::Path& GetPrefabFocusPath() const = 0; //! Returns the size of the path to the currently focused instance. - virtual const int GetPrefabFocusPathLength() = 0; + virtual const int GetPrefabFocusPathLength() const = 0; }; } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h index 5eda6ff2e3..aa27d87013 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h @@ -9,14 +9,19 @@ #pragma once #include +#include namespace AzToolsFramework::Prefab { - class PrefabFocusNotifications : public AZ::EBusTraits + //! Used to notify when the editor focus changes. + class PrefabFocusNotifications + : public AZ::EBusTraits { - public: - virtual ~PrefabFocusNotifications() = default; + protected: + ~PrefabFocusNotifications() = default; + public: + //! Triggered when the editor focus is changed to a different prefab. virtual void OnPrefabFocusChanged() = 0; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index c83c0016be..c1dd66ec7f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -49,9 +49,7 @@ namespace AzToolsFramework::Prefab connect(m_backButton, &QToolButton::clicked, this, [&]() { - int length = m_prefabFocusInterface->GetPrefabFocusPathLength(); - - if (length > 1) + if (int length = m_prefabFocusInterface->GetPrefabFocusPathLength(); length > 1) { m_prefabFocusInterface->FocusOnPathIndex(length - 2); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h index c874c7249f..5ce76d78ec 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h @@ -29,7 +29,7 @@ namespace AzToolsFramework::Prefab void Initialize(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton); - // PrefabFocusNotificationBus... + // PrefabFocusNotificationBus overrides ... void OnPrefabFocusChanged() override; private: From a94f7c222dee3317d942292b60041051ad0e7202 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 27 Sep 2021 09:23:26 +0100 Subject: [PATCH 051/115] Remove constructors without ViewportEditorModeTrackerInterface ptr. Signed-off-by: John --- .../ComponentMode/ComponentModeCollection.cpp | 10 ++------- .../ComponentMode/ComponentModeCollection.h | 3 +-- .../UnitTest/AzToolsFrameworkTestHelpers.h | 2 +- .../EditorDefaultSelection.cpp | 22 +++++-------------- .../EditorDefaultSelection.h | 3 +-- .../EditorPickEntitySelection.cpp | 18 +++------------ .../EditorPickEntitySelection.h | 3 +-- ...EditorTransformComponentSelectionTests.cpp | 2 +- 8 files changed, 16 insertions(+), 47 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index dddaa679bf..4d849466ee 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -218,10 +218,7 @@ namespace AzToolsFramework // this call to activate the component mode editor state should eventually replace the bus call in // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode // such that all of the notifications for activating/deactivating the different editor modes are in a central location - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); - } + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); // enable actions for the first/primary ComponentMode // note: if multiple ComponentModes are activated at the same time, actions @@ -299,10 +296,7 @@ namespace AzToolsFramework // this call to deactivate the component mode editor state should eventually replace the bus call in // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode // such that all of the notifications for activating/deactivating the different editor modes are in a central location - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); - } + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); // clear stored modes and builders for this ComponentMode // TLDR: avoid 'use after free' error diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h index b295d6103b..9e299d2323 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h @@ -26,8 +26,7 @@ namespace AzToolsFramework AZ_CLASS_ALLOCATOR_DECL /// @cond - ComponentModeCollection() = default; - ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker); + explicit ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~ComponentModeCollection() = default; ComponentModeCollection(const ComponentModeCollection&) = delete; ComponentModeCollection& operator=(const ComponentModeCollection&) = delete; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h index a67562af76..c4aefecce5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h @@ -172,7 +172,7 @@ namespace UnitTest { // create the default viewport (handles ComponentMode) AZStd::unique_ptr defaultSelection = - AZStd::make_unique(entityDataCache); + AZStd::make_unique(entityDataCache, viewportEditorModeTracker); // override the phantom widget so we can use out custom test widget defaultSelection->SetOverridePhantomWidget(&m_editorActions.m_componentModeWidget); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index 321549585a..30958cfbc1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -20,36 +20,26 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(EditorDefaultSelection, AZ::SystemAllocator, 0) - EditorDefaultSelection::EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache) + EditorDefaultSelection::EditorDefaultSelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) : m_phantomWidget(nullptr) , m_entityDataCache(entityDataCache) + , m_viewportEditorModeTracker(viewportEditorModeTracker) + , m_componentModeCollection(viewportEditorModeTracker) { ActionOverrideRequestBus::Handler::BusConnect(GetEntityContextId()); ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusConnect(); m_manipulatorManager = AZStd::make_shared(AzToolsFramework::g_mainManipulatorManagerId); m_transformComponentSelection = AZStd::make_unique(entityDataCache); - } - - EditorDefaultSelection::EditorDefaultSelection( - const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) - : EditorDefaultSelection(entityDataCache) - { - m_viewportEditorModeTracker = viewportEditorModeTracker; - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); - } + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); } EditorDefaultSelection::~EditorDefaultSelection() { ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusDisconnect(); ActionOverrideRequestBus::Handler::BusDisconnect(); - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); - } + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); } void EditorDefaultSelection::SetOverridePhantomWidget(QWidget* phantomOverrideWidget) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h index 6a53a2b186..e4c794e99e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h @@ -27,8 +27,7 @@ namespace AzToolsFramework AZ_CLASS_ALLOCATOR_DECL //! @cond - explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache); - explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); + EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); EditorDefaultSelection(const EditorDefaultSelection&) = delete; EditorDefaultSelection& operator=(const EditorDefaultSelection&) = delete; virtual ~EditorDefaultSelection(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp index 9306deb69d..1e0f42d01a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp @@ -16,20 +16,11 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(EditorPickEntitySelection, AZ::SystemAllocator, 0) - EditorPickEntitySelection::EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache) - : m_editorHelpers(AZStd::make_unique(entityDataCache)) - { - } - EditorPickEntitySelection::EditorPickEntitySelection( const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) - : EditorPickEntitySelection(entityDataCache) + : m_editorHelpers(AZStd::make_unique(entityDataCache)) + , m_viewportEditorModeTracker(viewportEditorModeTracker) { - m_viewportEditorModeTracker = viewportEditorModeTracker; - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); - } } EditorPickEntitySelection::~EditorPickEntitySelection() @@ -39,10 +30,7 @@ namespace AzToolsFramework ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, m_hoveredEntityId, false); } - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); - } + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); } // note: entityIdUnderCursor is the authoritative entityId we get each frame by querying diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h index 511111743a..62fa4161b7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h @@ -22,8 +22,7 @@ namespace AzToolsFramework public: AZ_CLASS_ALLOCATOR_DECL - explicit EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache); - explicit EditorPickEntitySelection( + EditorPickEntitySelection( const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~EditorPickEntitySelection(); diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index 1316523f29..b6170e4b89 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -346,7 +346,7 @@ namespace UnitTest [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); // When From 5ebe66c5b686b820b80c38b0be8a29240285cdb6 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 27 Sep 2021 13:10:47 +0100 Subject: [PATCH 052/115] Add integration tests for viewport editor modes. Signed-off-by: John --- .../EditorPickEntitySelection.cpp | 1 + .../Viewport/ViewportEditorModeTests.cpp | 111 +++++++++++++----- 2 files changed, 84 insertions(+), 28 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp index 1e0f42d01a..18eda140a0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp @@ -21,6 +21,7 @@ namespace AzToolsFramework : m_editorHelpers(AZStd::make_unique(entityDataCache)) , m_viewportEditorModeTracker(viewportEditorModeTracker) { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); } EditorPickEntitySelection::~EditorPickEntitySelection() diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index b2b75e22a7..371bfb2648 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -7,7 +7,9 @@ */ #include +#include #include +#include #include namespace UnitTest @@ -18,6 +20,7 @@ namespace UnitTest using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo; using ViewportId = ViewportEditorModeInfo::IdType; using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; + using ViewportEditorModeTrackerInterface = AzToolsFramework::ViewportEditorModeTrackerInterface; void ActivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) { @@ -47,6 +50,26 @@ namespace UnitTest } } + void ExpectOnlyModeActive(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) + { + for (auto modeIndex = 0; modeIndex < ViewportEditorModes::NumEditorModes; modeIndex++) + { + const auto currentMode = static_cast(modeIndex); + const bool expectedActive = (mode == currentMode); + EXPECT_EQ(editorModeState.IsModeActive(currentMode), expectedActive); + } + } + + void ExpectOnlyModeInactive(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) + { + for (auto modeIndex = 0; modeIndex < ViewportEditorModes::NumEditorModes; modeIndex++) + { + const auto currentMode = static_cast(modeIndex); + const bool expectedActive = (mode != currentMode); + EXPECT_EQ(editorModeState.IsModeActive(currentMode), expectedActive); + } + } + // Fixture for testing editor mode states class ViewportEditorModesTestsFixture : public ::testing::Test @@ -116,7 +139,7 @@ namespace UnitTest m_editorModes[mode].m_onEnter = true; } - virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onExit = true; } @@ -156,6 +179,16 @@ namespace UnitTest class ViewportEditorModeTrackerIntegrationTestFixture : public ToolsApplicationFixture { + public: + void SetUpEditorFixtureImpl() override + { + m_viewportEditorModeTracker = AZ::Interface::Get(); + ASSERT_NE(m_viewportEditorModeTracker, nullptr); + m_viewportEditorModes = m_viewportEditorModeTracker->GetViewportEditorModes({}); + } + + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; + const ViewportEditorModesInterface* m_viewportEditorModes = nullptr; }; TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4) @@ -174,38 +207,14 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); - - for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) - { - const auto editorMode = static_cast(mode); - if (editorMode == m_selectedEditorMode) - { - EXPECT_TRUE(m_editorModes.IsModeActive(static_cast(editorMode))); - } - else - { - EXPECT_FALSE(m_editorModes.IsModeActive(static_cast(editorMode))); - } - } + ExpectOnlyModeActive(m_editorModes, m_selectedEditorMode); } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { SetAllModesActive(m_editorModes); DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); - - for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) - { - const auto editorMode = static_cast(mode); - if (editorMode == m_selectedEditorMode) - { - EXPECT_FALSE(m_editorModes.IsModeActive(editorMode)); - } - else - { - EXPECT_TRUE(m_editorModes.IsModeActive(editorMode)); - } - } + ExpectOnlyModeInactive(m_editorModes, m_selectedEditorMode); } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively) @@ -502,7 +511,53 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, FOO) + TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, InitialViewportEditorModeIsDefault) { + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default); } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, EnteringComponentModeAfterInitialStateHasViewportEditorModesDefaultAndComponentModeActive) + { + // When component mode is entered + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, + AZStd::vector{}); + + bool inComponentMode = false; + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( + inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); + + // Expect to be in component mode + EXPECT_TRUE(inComponentMode); + + // Expect the default and component viewport editor modes to be active + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component)); + + // ExpeDo not expect ct the pick and focus viewport editor modes to be active + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick)); + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus)); + } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, + EnteringEditorPickEntitySelectionAfterInitialStateHasOnlyViewportEditorModePickModeActive) + { + // When entering pick mode + using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus; + EditorInteractionSystemViewportSelectionRequestBus::Event( + AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, + [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + { + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); + }); + + // Expect only the pick viewport editor mode to be active + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Pick); + } + + // FocusMode integration tests will follow (LYN-6995) + } // namespace UnitTest From 536ef46e2bc1e5e20e1f4f46ff6377c58726187f Mon Sep 17 00:00:00 2001 From: nggieber Date: Mon, 27 Sep 2021 07:12:10 -0700 Subject: [PATCH 053/115] Add Add Gem Repo Dialog Signed-off-by: nggieber --- .../Resources/ProjectManager.qss | 4 ++ .../Source/GemRepo/GemRepoAddDialog.cpp | 62 +++++++++++++++++++ .../Source/GemRepo/GemRepoAddDialog.h | 15 +++++ .../Source/GemRepo/GemRepoScreen.cpp | 45 +++++++++++--- .../Source/GemRepo/GemRepoScreen.h | 4 +- .../ProjectManager/Source/PythonBindings.cpp | 7 +++ .../ProjectManager/Source/PythonBindings.h | 1 + .../Source/PythonBindingsInterface.h | 7 +++ 8 files changed, 137 insertions(+), 8 deletions(-) diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 52cc784336..8bfd647a56 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -600,3 +600,7 @@ QProgressBar::chunk { #gemRepoInspector { background: #444444; } + +#gemRepoAddDialogInstructionTitleLabel { + font-size:14px; +} diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp index 31e98a965b..4525abb16b 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp @@ -7,12 +7,74 @@ */ #include +#include + +#include +#include +#include +#include namespace O3DE::ProjectManager { GemRepoAddDialog::GemRepoAddDialog(QWidget* parent) : QDialog(parent) { + setWindowTitle(tr("Add a User Repository")); + setModal(true); + QVBoxLayout* vLayout = new QVBoxLayout(); + vLayout->setContentsMargins(30, 30, 25, 10); + vLayout->setSpacing(0); + setLayout(vLayout); + + QLabel* instructionTitleLabel = new QLabel(tr("Enter a valid path to add a new user repository")); + instructionTitleLabel->setObjectName("gemRepoAddDialogInstructionTitleLabel"); + instructionTitleLabel->setAlignment(Qt::AlignLeft); + vLayout->addWidget(instructionTitleLabel); + + vLayout->addSpacing(10); + + QLabel* instructionContextLabel = new QLabel(tr("The path can be a Repository URL or a Local Path in your directory.")); + instructionContextLabel->setAlignment(Qt::AlignLeft); + vLayout->addWidget(instructionContextLabel); + + m_repoPath = new FormLineEditWidget(tr("Repository Path"), "", this); + m_repoPath->setFixedWidth(500); + vLayout->addWidget(m_repoPath); + + vLayout->addSpacing(40); + + QDialogButtonBox* dialogButtons = new QDialogButtonBox(); + dialogButtons->setObjectName("footer"); + vLayout->addWidget(dialogButtons); + + QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); + cancelButton->setProperty("secondary", true); + QPushButton* continueButton = dialogButtons->addButton(tr("Add"), QDialogButtonBox::ApplyRole); + + connect(cancelButton, &QPushButton::clicked, this, &GemRepoAddDialog::CancelButtonPressed); + connect(continueButton, &QPushButton::clicked, this, &GemRepoAddDialog::ContinueButtonPressed); + } + + QDialogButtonBox::ButtonRole GemRepoAddDialog::GetButtonResult() + { + return m_buttonResult; + } + + QString GemRepoAddDialog::GetRepoPath() + { + return m_repoPath->lineEdit()->text(); + } + + void GemRepoAddDialog::CancelButtonPressed() + { + m_buttonResult = QDialogButtonBox::RejectRole; + close(); + } + + void GemRepoAddDialog::ContinueButtonPressed() + { + m_buttonResult = QDialogButtonBox::ApplyRole; + close(); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h index 24c9b4b357..28530c5f0b 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h @@ -10,15 +10,30 @@ #if !defined(Q_MOC_RUN) #include + +#include #endif namespace O3DE::ProjectManager { + QT_FORWARD_DECLARE_CLASS(FormLineEditWidget) + class GemRepoAddDialog : public QDialog { public: explicit GemRepoAddDialog(QWidget* parent = nullptr); ~GemRepoAddDialog() = default; + + QDialogButtonBox::ButtonRole GetButtonResult(); + QString GetRepoPath(); + + private: + void CancelButtonPressed(); + void ContinueButtonPressed(); + + FormLineEditWidget* m_repoPath = nullptr; + + QDialogButtonBox::ButtonRole m_buttonResult = QDialogButtonBox::RejectRole; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 5838abf643..5e533414b0 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -70,6 +71,32 @@ namespace O3DE::ProjectManager }); } + void GemRepoScreen::HandleAddRepoButton() + { + GemRepoAddDialog* repoAddDialog = new GemRepoAddDialog(this); + repoAddDialog->exec(); + + if (repoAddDialog->GetButtonResult() == QDialogButtonBox::ApplyRole) + { + QString repoUrl = repoAddDialog->GetRepoPath(); + if (repoUrl.isEmpty()) + { + return; + } + + AZ::Outcome addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUrl); + if (addGemRepoResult.IsSuccess()) + { + Reinit(); + } + else + { + QMessageBox::critical(this, tr("Operation failed"), + QString("Failed to add gem repo: %1.\nError:\n%2").arg(repoUrl, addGemRepoResult.GetError().c_str())); + } + } + } + void GemRepoScreen::FillModel() { AZ::Outcome, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos(); @@ -114,10 +141,12 @@ namespace O3DE::ProjectManager hLayout->addStretch(); - m_AddRepoButton = new QPushButton(tr("Add Repository"), this); - m_AddRepoButton->setObjectName("gemRepoAddButton"); - m_AddRepoButton->setMinimumWidth(120); - hLayout->addWidget(m_AddRepoButton); + QPushButton* addRepoButton = new QPushButton(tr("Add Repository"), this); + addRepoButton->setObjectName("gemRepoAddButton"); + addRepoButton->setMinimumWidth(120); + hLayout->addWidget(addRepoButton); + + connect(addRepoButton, &QPushButton::clicked, this, &GemRepoScreen::HandleAddRepoButton); hLayout->addStretch(); @@ -165,9 +194,11 @@ namespace O3DE::ProjectManager topMiddleHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); - m_AddRepoButton = new QPushButton(tr("Add Repository"), this); - m_AddRepoButton->setObjectName("gemRepoAddButton"); - topMiddleHLayout->addWidget(m_AddRepoButton); + QPushButton* addRepoButton = new QPushButton(tr("Add Repository"), this); + addRepoButton->setObjectName("gemRepoAddButton"); + topMiddleHLayout->addWidget(addRepoButton); + + connect(addRepoButton, &QPushButton::clicked, this, &GemRepoScreen::HandleAddRepoButton); topMiddleHLayout->addSpacing(30); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h index ab679ad39b..fcbb59cceb 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h @@ -36,6 +36,9 @@ namespace O3DE::ProjectManager GemRepoModel* GetGemRepoModel() const { return m_gemRepoModel; } + public slots: + void HandleAddRepoButton(); + private: void FillModel(); QFrame* CreateNoReposContent(); @@ -53,6 +56,5 @@ namespace O3DE::ProjectManager QLabel* m_lastAllUpdateLabel; QPushButton* m_AllUpdateButton; - QPushButton* m_AddRepoButton; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 6f8ff9abce..aa3f957a2a 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -913,6 +913,13 @@ namespace O3DE::ProjectManager } } + AZ::Outcome PythonBindings::AddGemRepo(const QString& repoUri) + { + // o3de scripts need method added + (void)repoUri; + return AZ::Failure("Adding Gem Repo not implemented yet in o3de scripts."); + } + GemRepoInfo PythonBindings::GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath) { /* Placeholder Logic */ diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 3b766c3797..c216be0acb 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -57,6 +57,7 @@ namespace O3DE::ProjectManager AZ::Outcome> GetProjectTemplates(const QString& projectPath = {}) override; // Gem Repos + AZ::Outcome AddGemRepo(const QString& repoUri = {}) override; AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override; private: diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index 9fd3002f93..4baab85145 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -159,6 +159,13 @@ namespace O3DE::ProjectManager // Gem Repos + /** + * A gem repo to engine. Registers this gem repo with the current engine. + * @param repoUri the absolute filesystem path or url to the gem repo manifest file. + * @return An outcome with the success flag as well as an error message in case of a failure. + */ + virtual AZ::Outcome AddGemRepo(const QString& repoUri = {}) = 0; + /** * Get all available gem repo infos. Gathers all repos registered with the engine. * @return A list of gem repo infos. From 690f8e6925a13f097ef17e5e60ec9babb4c465f1 Mon Sep 17 00:00:00 2001 From: nggieber Date: Mon, 27 Sep 2021 07:31:32 -0700 Subject: [PATCH 054/115] Minor merge fix Signed-off-by: nggieber --- Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 63f92466b5..0d0605f750 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include #include @@ -35,7 +35,7 @@ namespace O3DE::ProjectManager QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); vLayout->setSpacing(0); - setLayout(vLayout); + setLayout(vLayout); m_contentStack = new QStackedWidget(this); From 0b5aaa297e69d123397c76f57075ef216f3f5f47 Mon Sep 17 00:00:00 2001 From: nggieber Date: Mon, 27 Sep 2021 07:40:33 -0700 Subject: [PATCH 055/115] Fix text alignment Signed-off-by: nggieber --- Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 0d0605f750..e2c03b6cc2 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -35,7 +35,7 @@ namespace O3DE::ProjectManager QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); vLayout->setSpacing(0); - setLayout(vLayout); + setLayout(vLayout); m_contentStack = new QStackedWidget(this); From 75e7758eedab7142137fd816a6e8a3971655bbd7 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 28 Sep 2021 08:57:14 +0100 Subject: [PATCH 056/115] Address PR comments. Signed-off-by: John --- .../EditorInteractionSystemComponent.cpp | 12 ++++-------- .../Tests/Viewport/ViewportEditorModeTests.cpp | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp index 7f84038ace..5d03231aab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp @@ -17,19 +17,15 @@ namespace AzToolsFramework EditorInteractionSystemComponent::EditorInteractionSystemComponent() : m_viewportEditorMode(AZStd::make_unique()) { - if (AZ::Interface::Get() == nullptr) - { - AZ::Interface::Register(m_viewportEditorMode.get()); - } + AZ_Assert(AZ::Interface::Get() == nullptr, "Unexpected registration of viewport editor mode tracker.") + AZ::Interface::Register(m_viewportEditorMode.get()); } EditorInteractionSystemComponent::~EditorInteractionSystemComponent() { m_interactionRequests.reset(); - if (AZ::Interface::Get() != nullptr) - { - AZ::Interface::Unregister(m_viewportEditorMode.get()); - } + AZ_Assert(AZ::Interface::Get() != nullptr, "Unexpected unregistration of viewport editor mode tracker.") + AZ::Interface::Unregister(m_viewportEditorMode.get()); } void EditorInteractionSystemComponent::Activate() diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 371bfb2648..866d88b7ba 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -535,7 +535,7 @@ namespace UnitTest EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component)); - // ExpeDo not expect ct the pick and focus viewport editor modes to be active + // Do not expect the pick and focus viewport editor modes to be active EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick)); EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus)); } From 25b16fc82cc1569bf09deb6b4313d42b1d75d743 Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Tue, 28 Sep 2021 12:25:07 -0700 Subject: [PATCH 057/115] Changed the DiffuseProbeGrid to an OBB Signed-off-by: dmcdiar --- .../DiffuseProbeGrid.cpp | 29 +++++++++++-------- .../DiffuseProbeGrid.h | 10 +++---- .../DiffuseProbeGridFeatureProcessor.cpp | 9 +++--- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp index 4d58948b98..a966eaddcb 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp @@ -128,8 +128,8 @@ namespace AZ void DiffuseProbeGrid::SetTransform(const AZ::Transform& transform) { - m_position = transform.GetTranslation(); - m_aabbWs = Aabb::CreateCenterHalfExtents(m_position, m_extents / 2.0f); + m_transform = transform; + m_obbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_extents / 2.0f); // probes need to be relocated since the grid position changed m_remainingRelocationIterations = DefaultNumRelocationIterations; @@ -145,7 +145,7 @@ namespace AZ void DiffuseProbeGrid::SetExtents(const AZ::Vector3& extents) { m_extents = extents; - m_aabbWs = Aabb::CreateCenterHalfExtents(m_position, m_extents / 2.0f); + m_obbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_extents / 2.0f); // recompute the number of probes since the extents changed UpdateProbeCount(); @@ -467,7 +467,10 @@ namespace AZ RHI::ShaderInputConstantIndex constantIndex; constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_probeGrid.origin")); - srg->SetConstant(constantIndex, m_position); + srg->SetConstant(constantIndex, m_transform.GetTranslation()); + + constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_probeGrid.rotation")); + srg->SetConstant(constantIndex, m_transform.GetRotation()); constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_probeGrid.numRaysPerProbe")); srg->SetConstant(constantIndex, m_numRaysPerProbe); @@ -760,14 +763,15 @@ namespace AZ RHI::ShaderInputImageIndex imageIndex; constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_modelToWorld")); - AZ::Matrix3x4 modelToWorld = AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(Matrix3x3::CreateIdentity(), m_position) * AZ::Matrix3x4::CreateScale(m_extents); + AZ::Matrix3x4 modelToWorld = AZ::Matrix3x4::CreateFromTransform(m_transform) * AZ::Matrix3x4::CreateScale(m_extents); m_renderObjectSrg->SetConstant(constantIndex, modelToWorld); - constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_aabbMin")); - m_renderObjectSrg->SetConstant(constantIndex, m_aabbWs.GetMin()); + constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_modelToWorldInverse")); + AZ::Matrix3x4 modelToWorldInverse = AZ::Matrix3x4::CreateFromTransform(m_transform).GetInverseFull(); + m_renderObjectSrg->SetConstant(constantIndex, modelToWorldInverse); - constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_aabbMax")); - m_renderObjectSrg->SetConstant(constantIndex, m_aabbWs.GetMax()); + constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_obbHalfLengths")); + m_renderObjectSrg->SetConstant(constantIndex, m_obbWs.GetHalfLengths()); constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_enableDiffuseGI")); m_renderObjectSrg->SetConstant(constantIndex, m_enabled); @@ -821,13 +825,14 @@ namespace AZ lod.m_screenCoverageMax = 1.0f; // update cullable bounds + Aabb aabbWs = Aabb::CreateFromObb(m_obbWs); Vector3 center; float radius; - m_aabbWs.GetAsSphere(center, radius); + aabbWs.GetAsSphere(center, radius); m_cullable.m_cullData.m_boundingSphere = Sphere(center, radius); - m_cullable.m_cullData.m_boundingObb = m_aabbWs.GetTransformedObb(AZ::Transform::CreateIdentity()); - m_cullable.m_cullData.m_visibilityEntry.m_boundingVolume = m_aabbWs; + m_cullable.m_cullData.m_boundingObb = aabbWs.GetTransformedObb(AZ::Transform::CreateIdentity()); + m_cullable.m_cullData.m_visibilityEntry.m_boundingVolume = aabbWs; m_cullable.m_cullData.m_visibilityEntry.m_userData = &m_cullable; m_cullable.m_cullData.m_visibilityEntry.m_typeFlags = AzFramework::VisibilityEntry::TYPE_RPI_Cullable; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h index 89e7173dd5..97c336ed41 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h @@ -72,7 +72,7 @@ namespace AZ const AZ::Vector3& GetExtents() const { return m_extents; } void SetExtents(const AZ::Vector3& extents); - const AZ::Aabb& GetAabbWs() const { return m_aabbWs; } + const AZ::Obb& GetObbWs() const { return m_obbWs; } bool ValidateProbeSpacing(const AZ::Vector3& newSpacing); const AZ::Vector3& GetProbeSpacing() const { return m_probeSpacing; } @@ -183,14 +183,14 @@ namespace AZ // scene RPI::Scene* m_scene = nullptr; - // probe grid position - AZ::Vector3 m_position = AZ::Vector3(0.0f, 0.0f, 0.0f); + // probe grid transform + AZ::Transform m_transform = AZ::Transform::CreateIdentity(); // extents of the probe grid AZ::Vector3 m_extents = AZ::Vector3(0.0f, 0.0f, 0.0f); - // probe grid AABB (world space), built from position and extents - AZ::Aabb m_aabbWs = AZ::Aabb::CreateNull(); + // probe grid OBB (world space), built from transform and extents + AZ::Obb m_obbWs; // per-axis spacing of probes in the grid AZ::Vector3 m_probeSpacing; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index d79240d4f1..4329fd556c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -154,10 +154,11 @@ namespace AZ // sort the probes by descending inner volume size, so the smallest volumes are rendered last auto sortFn = [](AZStd::shared_ptr const& probe1, AZStd::shared_ptr const& probe2) -> bool { - const Aabb& aabb1 = probe1->GetAabbWs(); - const Aabb& aabb2 = probe2->GetAabbWs(); - float size1 = aabb1.GetXExtent() * aabb1.GetZExtent() * aabb1.GetYExtent(); - float size2 = aabb2.GetXExtent() * aabb2.GetZExtent() * aabb2.GetYExtent(); + const Obb& obb1 = probe1->GetObbWs(); + const Obb& obb2 = probe2->GetObbWs(); + float size1 = obb1.GetHalfLengthX() * obb1.GetHalfLengthZ() * obb1.GetHalfLengthY(); + float size2 = obb2.GetHalfLengthX() * obb2.GetHalfLengthZ() * obb2.GetHalfLengthY(); + return (size1 > size2); }; From f6585a741c69083527b816bc40733c1d41dde9ce Mon Sep 17 00:00:00 2001 From: sweeneys Date: Tue, 28 Sep 2021 14:53:58 -0700 Subject: [PATCH 058/115] docstring updates Signed-off-by: sweeneys --- .../ly_test_tools/_internal/managers/platforms/linux.py | 2 +- .../ly_test_tools/launchers/platforms/linux/launcher.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py index 0cf213c746..cdbd379183 100644 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py @@ -59,7 +59,7 @@ class _LinuxResourceManager(AbstractResourceLocator): class LinuxWorkspaceManager(AbstractWorkspaceManager): """ - A Mac host WorkspaceManager. Contains Mac overridden functions for the AbstractWorkspaceManager class. + A Linux host WorkspaceManager. Contains Mac overridden functions for the AbstractWorkspaceManager class. Also creates a Mac host ResourceLocator for directory and build mappings. """ def __init__( diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py index 47a538d90e..210519d197 100644 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py @@ -147,7 +147,7 @@ class LinuxLauncher(Launcher): def check_returncode(self): # type: () -> None """ - Checks the returncode of the launcher if it exists. Raises a CrashError if the returncode is non-zero. Returns + Checks the return code of the launcher if it exists. Raises a CrashError if the returncode is non-zero. Returns None otherwise. This function must be called after exiting the launcher properly and NOT using its provided teardown(). Provided teardown() will always return a non-zero returncode and should not be checked. From ce334f9443ff37b4ba7b615f92e634a45d11fbc2 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 28 Sep 2021 17:48:36 -0700 Subject: [PATCH 059/115] Correctly set focused entity in case the root prefab instance is focused. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Prefab/PrefabFocusHandler.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index c17b58486a..9bfe64bc84 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -84,11 +84,20 @@ namespace AzToolsFramework::Prefab m_focusedInstance = focusedInstance; m_focusedTemplateId = focusedInstance->get().GetTemplateId(); - AZ::EntityId containerEntityId = focusedInstance->get().GetContainerEntityId(); + AZ::EntityId containerEntityId; - // Select the container entity - AzToolsFramework::SelectEntity(containerEntityId); + if (focusedInstance->get().GetParentInstance() != AZStd::nullopt) + { + containerEntityId = focusedInstance->get().GetContainerEntityId(); + // Select the container entity + AzToolsFramework::SelectEntity(containerEntityId); + } + else + { + containerEntityId = AZ::EntityId(); + } + // Focus on the descendants of the container entity if (FocusModeInterface* focusModeInterface = AZ::Interface::Get()) { @@ -96,7 +105,6 @@ namespace AzToolsFramework::Prefab } RefreshInstanceFocusList(); - PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); } From c204aa1abe9818a2624c4cb62c20616c20bb2eb9 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 28 Sep 2021 18:16:02 -0700 Subject: [PATCH 060/115] Change notification buses to be addressed on EntityContextId, and connect the handlers to the default id. Request interfaces should not need that id as they can retrieve it from the entityId. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../FocusMode/FocusModeNotificationBus.h | 15 ++++++++++++--- .../Prefab/PrefabFocusHandler.cpp | 4 ++++ .../Prefab/PrefabFocusNotificationBus.h | 13 ++++++++++--- .../UI/Outliner/EntityOutlinerTreeView.cpp | 7 ++++++- .../UI/Prefab/PrefabViewportFocusPathHandler.cpp | 10 ++++++++-- 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h index a16bb9a3ef..ab8629ac85 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h @@ -11,19 +11,28 @@ #include #include +#include + namespace AzToolsFramework { //! Used to notify when the editor focus changes. class FocusModeNotifications : public AZ::EBusTraits { - protected: - ~FocusModeNotifications() = default; - public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; + using BusIdType = AzFramework::EntityContextId; + ////////////////////////////////////////////////////////////////////////// + //! Triggered when the editor focus is changed to a different entity. //! @param entityId The entity the focus has been moved to. virtual void OnEditorFocusChanged(AZ::EntityId entityId) = 0; + + protected: + ~FocusModeNotifications() = default; }; using FocusModeNotificationBus = AZ::EBus; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 9bfe64bc84..3ce8065ae5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -96,6 +96,10 @@ namespace AzToolsFramework::Prefab else { containerEntityId = AZ::EntityId(); + + // Clear the selection + AzToolsFramework::SelectEntities({}); + } // Focus on the descendants of the container entity diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h index aa27d87013..31bab719e2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h @@ -17,12 +17,19 @@ namespace AzToolsFramework::Prefab class PrefabFocusNotifications : public AZ::EBusTraits { - protected: - ~PrefabFocusNotifications() = default; - public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; + using BusIdType = AzFramework::EntityContextId; + ////////////////////////////////////////////////////////////////////////// + //! Triggered when the editor focus is changed to a different prefab. virtual void OnPrefabFocusChanged() = 0; + + protected: + ~PrefabFocusNotifications() = default; }; using PrefabFocusNotificationBus = AZ::EBus; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp index 6a40b3be3a..4364ae1efc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp @@ -39,7 +39,12 @@ namespace AzToolsFramework AZ_Assert((m_editorEntityFrameworkInterface != nullptr), "EntityOutlinerTreeView requires a EditorEntityFrameworkInterface instance on Construction."); - FocusModeNotificationBus::Handler::BusConnect(); + + AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( + editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); + + FocusModeNotificationBus::Handler::BusConnect(editorEntityContextId); viewport()->setMouseTracking(true); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index c1dd66ec7f..09d0579dab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -6,15 +6,21 @@ * */ -#include #include +#include +#include + namespace AzToolsFramework::Prefab { PrefabViewportFocusPathHandler::PrefabViewportFocusPathHandler() { // Connect to Prefab Focus Notifications - PrefabFocusNotificationBus::Handler::BusConnect(); + AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( + editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); + + PrefabFocusNotificationBus::Handler::BusConnect(editorEntityContextId); } PrefabViewportFocusPathHandler::~PrefabViewportFocusPathHandler() From 16e66cfa7145d077af7a593cac51c75e6b871d83 Mon Sep 17 00:00:00 2001 From: nggieber Date: Tue, 28 Sep 2021 18:37:44 -0700 Subject: [PATCH 061/115] Addressed review feedback Signed-off-by: nggieber --- .../Resources/ProjectManager.qss | 4 +++ .../Source/GemRepo/GemRepoAddDialog.cpp | 27 +++++-------------- .../Source/GemRepo/GemRepoAddDialog.h | 8 ------ .../Source/GemRepo/GemRepoScreen.cpp | 7 +++-- .../ProjectManager/Source/PythonBindings.h | 2 +- .../Source/PythonBindingsInterface.h | 2 +- 6 files changed, 15 insertions(+), 35 deletions(-) diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 8898a94652..eeed316cbc 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -617,6 +617,10 @@ QProgressBar::chunk { font-size:14px; } +#addGemRepoDialog #formFrame { + margin-left:0px; +} + /************** Gem Repo Inspector **************/ #gemRepoInspectorNameLabel { diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp index 4525abb16b..9e40a2b231 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace O3DE::ProjectManager @@ -21,6 +22,7 @@ namespace O3DE::ProjectManager { setWindowTitle(tr("Add a User Repository")); setModal(true); + setObjectName("addGemRepoDialog"); QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setContentsMargins(30, 30, 25, 10); @@ -39,7 +41,7 @@ namespace O3DE::ProjectManager vLayout->addWidget(instructionContextLabel); m_repoPath = new FormLineEditWidget(tr("Repository Path"), "", this); - m_repoPath->setFixedWidth(500); + m_repoPath->setFixedWidth(600); vLayout->addWidget(m_repoPath); vLayout->addSpacing(40); @@ -50,31 +52,14 @@ namespace O3DE::ProjectManager QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); cancelButton->setProperty("secondary", true); - QPushButton* continueButton = dialogButtons->addButton(tr("Add"), QDialogButtonBox::ApplyRole); + QPushButton* applyButton = dialogButtons->addButton(tr("Add"), QDialogButtonBox::ApplyRole); - connect(cancelButton, &QPushButton::clicked, this, &GemRepoAddDialog::CancelButtonPressed); - connect(continueButton, &QPushButton::clicked, this, &GemRepoAddDialog::ContinueButtonPressed); - } - - QDialogButtonBox::ButtonRole GemRepoAddDialog::GetButtonResult() - { - return m_buttonResult; + connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject); + connect(applyButton, &QPushButton::clicked, this, &QDialog::accept); } QString GemRepoAddDialog::GetRepoPath() { return m_repoPath->lineEdit()->text(); } - - void GemRepoAddDialog::CancelButtonPressed() - { - m_buttonResult = QDialogButtonBox::RejectRole; - close(); - } - - void GemRepoAddDialog::ContinueButtonPressed() - { - m_buttonResult = QDialogButtonBox::ApplyRole; - close(); - } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h index 28530c5f0b..38b9bf68eb 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h @@ -10,8 +10,6 @@ #if !defined(Q_MOC_RUN) #include - -#include #endif namespace O3DE::ProjectManager @@ -25,15 +23,9 @@ namespace O3DE::ProjectManager explicit GemRepoAddDialog(QWidget* parent = nullptr); ~GemRepoAddDialog() = default; - QDialogButtonBox::ButtonRole GetButtonResult(); QString GetRepoPath(); private: - void CancelButtonPressed(); - void ContinueButtonPressed(); - FormLineEditWidget* m_repoPath = nullptr; - - QDialogButtonBox::ButtonRole m_buttonResult = QDialogButtonBox::RejectRole; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index e2c03b6cc2..9c432884e6 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -75,9 +75,8 @@ namespace O3DE::ProjectManager void GemRepoScreen::HandleAddRepoButton() { GemRepoAddDialog* repoAddDialog = new GemRepoAddDialog(this); - repoAddDialog->exec(); - if (repoAddDialog->GetButtonResult() == QDialogButtonBox::ApplyRole) + if (repoAddDialog->exec() == QDialog::DialogCode::Accepted) { QString repoUrl = repoAddDialog->GetRepoPath(); if (repoUrl.isEmpty()) @@ -93,7 +92,7 @@ namespace O3DE::ProjectManager else { QMessageBox::critical(this, tr("Operation failed"), - QString("Failed to add gem repo: %1.\nError:\n%2").arg(repoUrl, addGemRepoResult.GetError().c_str())); + QString("Failed to add gem repo: %1.
Error:
%2").arg(repoUrl, addGemRepoResult.GetError().c_str())); } } } @@ -112,7 +111,7 @@ namespace O3DE::ProjectManager } else { - QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str())); + QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.
Error:
%2").arg(allGemRepoInfosResult.GetError().c_str())); } } diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index c216be0acb..42f04ed6e6 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -57,7 +57,7 @@ namespace O3DE::ProjectManager AZ::Outcome> GetProjectTemplates(const QString& projectPath = {}) override; // Gem Repos - AZ::Outcome AddGemRepo(const QString& repoUri = {}) override; + AZ::Outcome AddGemRepo(const QString& repoUri) override; AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override; private: diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index 5a008c46df..92139f3df5 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -165,7 +165,7 @@ namespace O3DE::ProjectManager * @param repoUri the absolute filesystem path or url to the gem repo manifest file. * @return An outcome with the success flag as well as an error message in case of a failure. */ - virtual AZ::Outcome AddGemRepo(const QString& repoUri = {}) = 0; + virtual AZ::Outcome AddGemRepo(const QString& repoUri) = 0; /** * Get all available gem repo infos. Gathers all repos registered with the engine. From 9a325c657de678bd59f2d08aa58771cf84fd9e31 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 28 Sep 2021 18:41:46 -0700 Subject: [PATCH 062/115] Add EntityContextId argument to focus interface functions that don't deal with entityIds. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../FocusMode/FocusModeInterface.h | 4 ++-- .../FocusMode/FocusModeSystemComponent.cpp | 4 ++-- .../FocusMode/FocusModeSystemComponent.h | 4 ++-- .../Prefab/PrefabFocusHandler.cpp | 11 ++++++----- .../Prefab/PrefabFocusHandler.h | 10 +++++----- .../Prefab/PrefabFocusInterface.h | 12 +++++++----- .../Prefab/PrefabViewportFocusPathHandler.cpp | 17 ++++++++--------- .../UI/Prefab/PrefabViewportFocusPathHandler.h | 4 ++++ 8 files changed, 36 insertions(+), 30 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h index a4b90f95b7..d7da1da8b3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h @@ -26,11 +26,11 @@ namespace AzToolsFramework virtual void SetFocusRoot(AZ::EntityId entityId) = 0; //! Clears the Editor focus, allowing the user to select the whole level again. - virtual void ClearFocusRoot() = 0; + virtual void ClearFocusRoot(AzFramework::EntityContextId entityContextId) = 0; //! Returns the entity id of the root of the current Editor focus. //! @return The entity id of the root of the Editor focus, or an invalid entity id if no focus is set. - virtual AZ::EntityId GetFocusRoot() = 0; + virtual AZ::EntityId GetFocusRoot(AzFramework::EntityContextId entityContextId) = 0; //! Returns whether the entity id provided is part of the focused sub-tree. virtual bool IsInFocusSubTree(AZ::EntityId entityId) const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp index f6afc3bff5..d1c4d37821 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp @@ -76,12 +76,12 @@ namespace AzToolsFramework // TODO - If m_focusRoot != AZ::EntityId(), activate focus mode via ViewportEditorModeTrackerInterface; else, deactivate focus mode } - void FocusModeSystemComponent::ClearFocusRoot() + void FocusModeSystemComponent::ClearFocusRoot([[maybe_unused]] AzFramework::EntityContextId entityContextId) { SetFocusRoot(AZ::EntityId()); } - AZ::EntityId FocusModeSystemComponent::GetFocusRoot() + AZ::EntityId FocusModeSystemComponent::GetFocusRoot([[maybe_unused]] AzFramework::EntityContextId entityContextId) { return m_focusRoot; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.h index 27ddebe1ed..dabaa6aaf4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.h @@ -40,8 +40,8 @@ namespace AzToolsFramework // FocusModeInterface overrides ... void SetFocusRoot(AZ::EntityId entityId) override; - void ClearFocusRoot() override; - AZ::EntityId GetFocusRoot() override; + void ClearFocusRoot(AzFramework::EntityContextId entityContextId) override; + AZ::EntityId GetFocusRoot(AzFramework::EntityContextId entityContextId) override; bool IsInFocusSubTree(AZ::EntityId entityId) const override; private: diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 3ce8065ae5..4e58bbdf05 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -60,7 +60,7 @@ namespace AzToolsFramework::Prefab return FocusOnPrefabInstance(focusedInstance); } - PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex(int index) + PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex([[maybe_unused]] AzFramework::EntityContextId entityContextId, int index) { if (index < 0 || index >= m_instanceFocusVector.size()) { @@ -115,12 +115,13 @@ namespace AzToolsFramework::Prefab return AZ::Success(); } - TemplateId PrefabFocusHandler::GetFocusedPrefabTemplateId() const + TemplateId PrefabFocusHandler::GetFocusedPrefabTemplateId([[maybe_unused]] AzFramework::EntityContextId entityContextId) const { return m_focusedTemplateId; } - InstanceOptionalReference PrefabFocusHandler::GetFocusedPrefabInstance() const + InstanceOptionalReference PrefabFocusHandler::GetFocusedPrefabInstance( + [[maybe_unused]] AzFramework::EntityContextId entityContextId) const { return m_focusedInstance; } @@ -143,12 +144,12 @@ namespace AzToolsFramework::Prefab return instance.has_value() && (&instance->get() == &m_focusedInstance->get()); } - const AZ::IO::Path& PrefabFocusHandler::GetPrefabFocusPath() const + const AZ::IO::Path& PrefabFocusHandler::GetPrefabFocusPath([[maybe_unused]] AzFramework::EntityContextId entityContextId) const { return m_instanceFocusPath; } - const int PrefabFocusHandler::GetPrefabFocusPathLength() const + const int PrefabFocusHandler::GetPrefabFocusPathLength([[maybe_unused]] AzFramework::EntityContextId entityContextId) const { return aznumeric_cast(m_instanceFocusVector.size()); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index 0362e2d66d..2ccec36882 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -32,12 +32,12 @@ namespace AzToolsFramework::Prefab // PrefabFocusInterface overrides ... PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override; - PrefabFocusOperationResult FocusOnPathIndex(int index) override; - TemplateId GetFocusedPrefabTemplateId() const override; - InstanceOptionalReference GetFocusedPrefabInstance() const override; + PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) override; + TemplateId GetFocusedPrefabTemplateId(AzFramework::EntityContextId entityContextId) const override; + InstanceOptionalReference GetFocusedPrefabInstance(AzFramework::EntityContextId entityContextId) const override; bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const override; - const AZ::IO::Path& GetPrefabFocusPath() const override; - const int GetPrefabFocusPathLength() const override; + const AZ::IO::Path& GetPrefabFocusPath(AzFramework::EntityContextId entityContextId) const override; + const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const override; // EditorEntityContextNotificationBus overrides ... void OnEntityStreamLoadSuccess() override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h index 3efd2d4deb..1c0f4f85e9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h @@ -11,6 +11,8 @@ #include #include +#include + #include #include @@ -30,13 +32,13 @@ namespace AzToolsFramework::Prefab //! Set the focused prefab instance to the instance at position index of the current path. //! @param index The index of the instance in the current path that we want the prefab system to focus on. - virtual PrefabFocusOperationResult FocusOnPathIndex(int index) = 0; + virtual PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) = 0; //! Returns the template id of the instance the prefab system is focusing on. - virtual TemplateId GetFocusedPrefabTemplateId() const = 0; + virtual TemplateId GetFocusedPrefabTemplateId(AzFramework::EntityContextId entityContextId) const = 0; //! Returns a reference to the instance the prefab system is focusing on. - virtual InstanceOptionalReference GetFocusedPrefabInstance() const = 0; + virtual InstanceOptionalReference GetFocusedPrefabInstance(AzFramework::EntityContextId entityContextId) const = 0; //! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants. //! @param entityId The entityId of the queried entity. @@ -45,10 +47,10 @@ namespace AzToolsFramework::Prefab //! Returns the path from the root instance to the currently focused instance. //! @return A path composed from the names of the container entities for the instance path. - virtual const AZ::IO::Path& GetPrefabFocusPath() const = 0; + virtual const AZ::IO::Path& GetPrefabFocusPath(AzFramework::EntityContextId entityContextId) const = 0; //! Returns the size of the path to the currently focused instance. - virtual const int GetPrefabFocusPathLength() const = 0; + virtual const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const = 0; }; } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index 09d0579dab..6b0de5dc53 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -8,19 +8,18 @@ #include -#include #include namespace AzToolsFramework::Prefab { PrefabViewportFocusPathHandler::PrefabViewportFocusPathHandler() { - // Connect to Prefab Focus Notifications - AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + // Get default EntityContextId AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( - editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); + m_editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); - PrefabFocusNotificationBus::Handler::BusConnect(editorEntityContextId); + // Connect to Prefab Focus Notifications + PrefabFocusNotificationBus::Handler::BusConnect(m_editorEntityContextId); } PrefabViewportFocusPathHandler::~PrefabViewportFocusPathHandler() @@ -47,7 +46,7 @@ namespace AzToolsFramework::Prefab connect(m_breadcrumbsWidget, &AzQtComponents::BreadCrumbs::linkClicked, this, [&](const QString&, int linkIndex) { - m_prefabFocusInterface->FocusOnPathIndex(linkIndex); + m_prefabFocusInterface->FocusOnPathIndex(m_editorEntityContextId, linkIndex); } ); @@ -55,9 +54,9 @@ namespace AzToolsFramework::Prefab connect(m_backButton, &QToolButton::clicked, this, [&]() { - if (int length = m_prefabFocusInterface->GetPrefabFocusPathLength(); length > 1) + if (int length = m_prefabFocusInterface->GetPrefabFocusPathLength(m_editorEntityContextId); length > 1) { - m_prefabFocusInterface->FocusOnPathIndex(length - 2); + m_prefabFocusInterface->FocusOnPathIndex(m_editorEntityContextId, length - 2); } } ); @@ -66,7 +65,7 @@ namespace AzToolsFramework::Prefab void PrefabViewportFocusPathHandler::OnPrefabFocusChanged() { // Push new Path - m_breadcrumbsWidget->pushPath(m_prefabFocusInterface->GetPrefabFocusPath().c_str()); + m_breadcrumbsWidget->pushPath(m_prefabFocusInterface->GetPrefabFocusPath(m_editorEntityContextId).c_str()); } } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h index 5ce76d78ec..f1d09311da 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h @@ -8,6 +8,8 @@ #pragma once +#include + #include #include @@ -36,6 +38,8 @@ namespace AzToolsFramework::Prefab AzQtComponents::BreadCrumbs* m_breadcrumbsWidget = nullptr; QToolButton* m_backButton = nullptr; + AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + PrefabFocusInterface* m_prefabFocusInterface = nullptr; }; } // namespace AzToolsFramework::Prefab From 34def643a206bb38db0b351e3c246b8145d0160d Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 28 Sep 2021 21:30:06 -0700 Subject: [PATCH 063/115] In Slice mode, don't instantiate the handler, and also hide and disable the breadcrumbs widgets. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- Code/Editor/ViewportTitleDlg.cpp | 24 +++++++++++++++++++++++- Code/Editor/ViewportTitleDlg.h | 2 +- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 0c5c45e5c8..f5a8834656 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -15,6 +15,7 @@ #include "ViewportTitleDlg.h" // Qt +#include #include #include @@ -38,6 +39,7 @@ #include #include +#include #include #include @@ -145,6 +147,11 @@ CViewportTitleDlg::~CViewportTitleDlg() AZ::VR::VREventBus::Handler::BusDisconnect(); GetISystem()->GetISystemEventDispatcher()->RemoveListener(this); GetIEditor()->UnregisterNotifyListener(this); + + if (m_prefabViewportFocusPathHandler) + { + delete m_prefabViewportFocusPathHandler; + } } void CViewportTitleDlg::SetupCameraDropdownMenu() @@ -312,7 +319,22 @@ void CViewportTitleDlg::OnInitDialog() m_cameraSpeed->setFixedWidth(width); - m_prefabViewportFocusPathHandler.Initialize(m_ui->m_prefabFocusPath, m_ui->m_prefabFocusBackButton); + 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 + { + m_ui->m_prefabFocusPath->setEnabled(false); + m_ui->m_prefabFocusBackButton->setEnabled(false); + m_ui->m_prefabFocusPath->hide(); + m_ui->m_prefabFocusBackButton->hide(); + } + } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/ViewportTitleDlg.h b/Code/Editor/ViewportTitleDlg.h index dfdf567a39..6996fe7750 100644 --- a/Code/Editor/ViewportTitleDlg.h +++ b/Code/Editor/ViewportTitleDlg.h @@ -177,7 +177,7 @@ protected: QWidgetAction* m_gridSizeActionWidget = nullptr; QWidgetAction* m_angleSizeActionWidget = nullptr; - AzToolsFramework::Prefab::PrefabViewportFocusPathHandler m_prefabViewportFocusPathHandler; + AzToolsFramework::Prefab::PrefabViewportFocusPathHandler* m_prefabViewportFocusPathHandler = nullptr; QScopedPointer m_ui; }; From c8d2f74ca14f2b6bbc677aa25506ba33cb33a65a Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Tue, 28 Sep 2021 22:05:26 -0700 Subject: [PATCH 064/115] Added backward-compatible support for the old "id" key in material type files, which is being renamed to "name". This required the use of custom serializers, because the JSON serialization system does not have any means of supporting field name aliases through SerializeContext. Testing: RPI unit test pass and AtomSampleViewer material screenshot test script passes. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../MaterialPropertyConnectionSerializer.h | 38 +++++ .../MaterialPropertyGroupSerializer.h | 38 +++++ .../Atom/RPI.Edit/Material/MaterialUtils.h | 18 +++ .../MaterialPropertyConnectionSerializer.cpp | 126 ++++++++++++++++ .../MaterialPropertyGroupSerializer.cpp | 125 +++++++++++++++ .../Material/MaterialPropertySerializer.cpp | 46 +++--- .../Material/MaterialTypeSourceData.cpp | 24 +-- .../RPI.Edit/Material/MaterialUtils.cpp | 25 +++ .../MaterialPropertySerializerTests.cpp | 35 +++++ .../Material/MaterialTypeSourceDataTests.cpp | 142 ++++++++++++++++++ Gems/Atom/RPI/Code/atom_rpi_edit_files.cmake | 4 + 11 files changed, 584 insertions(+), 37 deletions(-) create mode 100644 Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyConnectionSerializer.h create mode 100644 Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyGroupSerializer.h create mode 100644 Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyConnectionSerializer.cpp create mode 100644 Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyGroupSerializer.cpp diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyConnectionSerializer.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyConnectionSerializer.h new file mode 100644 index 0000000000..44b8805667 --- /dev/null +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyConnectionSerializer.h @@ -0,0 +1,38 @@ +/* + * 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 + +namespace AZ +{ + class ReflectContext; + + namespace RPI + { + //! The property connection itself is rather simple, but we need this custom serializer to provide backward compatibility + //! for when the "id" key was changed to "name". If the JSON serialization system is ever updated to provide built-in + //! support for versioning, then we can probably remove this class. + class JsonMaterialPropertyConnectionSerializer + : public BaseJsonSerializer + { + public: + AZ_RTTI(JsonMaterialPropertyConnectionSerializer, "{2B7F00CF-51F7-4409-9C0E-914E59696FB9}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + JsonDeserializerContext& context) override; + + JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, + const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) override; + }; + + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyGroupSerializer.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyGroupSerializer.h new file mode 100644 index 0000000000..138dace86a --- /dev/null +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyGroupSerializer.h @@ -0,0 +1,38 @@ +/* + * 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 + +namespace AZ +{ + class ReflectContext; + + namespace RPI + { + //! The property group itself is rather simple, but we need this custom serializer to provide backward compatibility + //! for when the "id" key was changed to "name". If the JSON serialization system is ever updated to provide built-in + //! support for versioning, then we can probably remove this class. + class JsonMaterialPropertyGroupSerializer + : public BaseJsonSerializer + { + public: + AZ_RTTI(JsonMaterialPropertyGroupSerializer, "{74C56BBC-2084-46AF-9393-04C2FBDF6B20}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + JsonDeserializerContext& context) override; + + JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, + const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) override; + }; + + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialUtils.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialUtils.h index 7801e0c3a7..d12e848a02 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialUtils.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialUtils.h @@ -15,6 +15,13 @@ namespace AZ { + class JsonDeserializerContext; + + namespace JsonSerializationResult + { + union ResultCode; + } + namespace RPI { class MaterialTypeSourceData; @@ -35,6 +42,17 @@ namespace AZ //! @param filePath a relative path if document is provided, an absolute path if document is not provided. //! @param document the loaded json document. AZ::Outcome LoadMaterialTypeSourceData(const AZStd::string& filePath, const rapidjson::Value* document = nullptr); + + //! Utility function for custom JSON serializers to report results as "Skipped" when encountering keys that aren't recognized + //! as part of the custom format. + //! @param acceptedFieldNames an array of names that are recognized by the custom format + //! @param acceptedFieldNameCount the number of elements in @acceptedFieldNames + //! @param object the JSON object being loaded + //! @param context the common JsonDeserializerContext that is central to the serialization process + //! @param result the ResultCode that well be updated with the Outcomes "Skipped" if an unrecognized field is encountered + void CheckForUnrecognizedJsonFields( + const AZStd::string_view* acceptedFieldNames, uint32_t acceptedFieldNameCount, + const rapidjson::Value& object, JsonDeserializerContext& context, JsonSerializationResult::ResultCode& result); } } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyConnectionSerializer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyConnectionSerializer.cpp new file mode 100644 index 0000000000..a0be7b9dca --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyConnectionSerializer.cpp @@ -0,0 +1,126 @@ +/* + * 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 AZ +{ + namespace RPI + { + namespace JsonMaterialPropertyConnectionSerializerInternal + { + namespace Field + { + static constexpr const char type[] = "type"; + static constexpr const char name[] = "name"; + static constexpr const char id[] = "id"; // For backward compatibility + static constexpr const char shaderIndex[] = "shaderIndex"; + } + + static const AZStd::string_view AcceptedFields[] = + { + Field::type, + Field::name, + Field::id, + Field::shaderIndex + }; + } + + AZ_CLASS_ALLOCATOR_IMPL(JsonMaterialPropertyConnectionSerializer, SystemAllocator, 0); + + JsonSerializationResult::Result JsonMaterialPropertyConnectionSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, JsonDeserializerContext& context) + { + namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertyConnectionSerializerInternal; + + AZ_Assert(azrtti_typeid() == outputValueTypeId, + "Unable to deserialize material property connection to json because the provided type is %s", + outputValueTypeId.ToString().c_str()); + AZ_UNUSED(outputValueTypeId); + + MaterialTypeSourceData::PropertyConnection* propertyConnection = reinterpret_cast(outputValue); + AZ_Assert(propertyConnection, "Output value for JsonMaterialPropertyConnectionSerializer can't be null."); + + JSR::ResultCode result(JSR::Tasks::ReadField); + + if (!inputValue.IsObject()) + { + return context.Report(JsonSerializationResult::Tasks::ReadField, JsonSerializationResult::Outcomes::Unsupported, "Property connection must be a JSON object."); + } + + MaterialUtils::CheckForUnrecognizedJsonFields(AcceptedFields, AZ_ARRAY_SIZE(AcceptedFields), inputValue, context, result); + + result.Combine(ContinueLoadingFromJsonObjectField(&propertyConnection->m_type, azrtti_typeid(), inputValue, Field::type, context)); + + JsonSerializationResult::ResultCode nameResult = ContinueLoadingFromJsonObjectField(&propertyConnection->m_fieldName, azrtti_typeid(), inputValue, Field::name, context); + if (nameResult.GetOutcome() == JsonSerializationResult::Outcomes::DefaultsUsed) + { + // This "id" key is for backward compatibility. + result.Combine(ContinueLoadingFromJsonObjectField(&propertyConnection->m_fieldName, azrtti_typeid(), inputValue, Field::id, context)); + } + else + { + result.Combine(nameResult); + } + + result.Combine(ContinueLoadingFromJsonObjectField(&propertyConnection->m_shaderIndex, azrtti_typeid(), inputValue, Field::shaderIndex, context)); + + if (result.GetProcessing() == JsonSerializationResult::Processing::Completed) + { + return context.Report(result, "Successfully loaded property connection."); + } + else + { + return context.Report(result, "Partially loaded property connection."); + } + } + + + JsonSerializationResult::Result JsonMaterialPropertyConnectionSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, + [[maybe_unused]] const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) + { + namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertyConnectionSerializerInternal; + + AZ_Assert(azrtti_typeid() == valueTypeId, + "Unable to serialize material property connection to json because the provided type is %s", + valueTypeId.ToString().c_str()); + AZ_UNUSED(valueTypeId); + + const MaterialTypeSourceData::PropertyConnection* propertyConnection = reinterpret_cast(inputValue); + AZ_Assert(propertyConnection, "Input value for JsonMaterialPropertyConnectionSerializer can't be null."); + + JSR::ResultCode result(JSR::Tasks::WriteValue); + + outputValue.SetObject(); + + MaterialTypeSourceData::PropertyConnection defaultConnection; + + result.Combine(ContinueStoringToJsonObjectField(outputValue, Field::type, &propertyConnection->m_type, &defaultConnection.m_type, azrtti_typeid(), context)); + result.Combine(ContinueStoringToJsonObjectField(outputValue, Field::name, &propertyConnection->m_fieldName, &defaultConnection.m_fieldName, azrtti_typeid(), context)); + result.Combine(ContinueStoringToJsonObjectField(outputValue, Field::shaderIndex, &propertyConnection->m_shaderIndex, &defaultConnection.m_shaderIndex, azrtti_typeid(), context)); + + if (result.GetProcessing() == JsonSerializationResult::Processing::Completed) + { + return context.Report(result, "Successfully stored property connection."); + } + else + { + return context.Report(result, "Partially stored property connection."); + } + } + + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyGroupSerializer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyGroupSerializer.cpp new file mode 100644 index 0000000000..b54ba012d4 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyGroupSerializer.cpp @@ -0,0 +1,125 @@ +/* + * 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 AZ +{ + namespace RPI + { + namespace JsonMaterialPropertyGroupSerializerInternal + { + namespace Field + { + static constexpr const char name[] = "name"; + static constexpr const char id[] = "id"; // For backward compatibility + static constexpr const char displayName[] = "displayName"; + static constexpr const char description[] = "description"; + } + + static const AZStd::string_view AcceptedFields[] = + { + Field::name, + Field::id, + Field::displayName, + Field::description + }; + } + + AZ_CLASS_ALLOCATOR_IMPL(JsonMaterialPropertyGroupSerializer, SystemAllocator, 0); + + JsonSerializationResult::Result JsonMaterialPropertyGroupSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, JsonDeserializerContext& context) + { + namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertyGroupSerializerInternal; + + AZ_Assert(azrtti_typeid() == outputValueTypeId, + "Unable to deserialize material property group to json because the provided type is %s", + outputValueTypeId.ToString().c_str()); + AZ_UNUSED(outputValueTypeId); + + MaterialTypeSourceData::GroupDefinition* propertyGroup = reinterpret_cast(outputValue); + AZ_Assert(propertyGroup, "Output value for JsonMaterialPropertyGroupSerializer can't be null."); + + JSR::ResultCode result(JSR::Tasks::ReadField); + + if (!inputValue.IsObject()) + { + return context.Report(JsonSerializationResult::Tasks::ReadField, JsonSerializationResult::Outcomes::Unsupported, "Property group must be a JSON object."); + } + + MaterialUtils::CheckForUnrecognizedJsonFields(AcceptedFields, AZ_ARRAY_SIZE(AcceptedFields), inputValue, context, result); + + JsonSerializationResult::ResultCode nameResult = ContinueLoadingFromJsonObjectField(&propertyGroup->m_name, azrtti_typeid(), inputValue, Field::name, context); + if (nameResult.GetOutcome() == JsonSerializationResult::Outcomes::DefaultsUsed) + { + // This "id" key is for backward compatibility. + result.Combine(ContinueLoadingFromJsonObjectField(&propertyGroup->m_name, azrtti_typeid(), inputValue, Field::id, context)); + } + else + { + result.Combine(nameResult); + } + + result.Combine(ContinueLoadingFromJsonObjectField(&propertyGroup->m_displayName, azrtti_typeid(), inputValue, Field::displayName, context)); + result.Combine(ContinueLoadingFromJsonObjectField(&propertyGroup->m_description, azrtti_typeid(), inputValue, Field::description, context)); + + if (result.GetProcessing() == JsonSerializationResult::Processing::Completed) + { + return context.Report(result, "Successfully loaded property group."); + } + else + { + return context.Report(result, "Partially loaded property group."); + } + } + + + JsonSerializationResult::Result JsonMaterialPropertyGroupSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, + [[maybe_unused]] const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) + { + namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertyGroupSerializerInternal; + + AZ_Assert(azrtti_typeid() == valueTypeId, + "Unable to serialize material property group to json because the provided type is %s", + valueTypeId.ToString().c_str()); + AZ_UNUSED(valueTypeId); + + const MaterialTypeSourceData::GroupDefinition* propertyGroup = reinterpret_cast(inputValue); + AZ_Assert(propertyGroup, "Input value for JsonMaterialPropertyGroupSerializer can't be null."); + + JSR::ResultCode result(JSR::Tasks::WriteValue); + + outputValue.SetObject(); + + AZStd::string defaultEmpty; + + result.Combine(ContinueStoringToJsonObjectField(outputValue, Field::name, &propertyGroup->m_name, &defaultEmpty, azrtti_typeid(), context)); + result.Combine(ContinueStoringToJsonObjectField(outputValue, Field::displayName, &propertyGroup->m_displayName, &defaultEmpty, azrtti_typeid(), context)); + result.Combine(ContinueStoringToJsonObjectField(outputValue, Field::description, &propertyGroup->m_description, &defaultEmpty, azrtti_typeid(), context)); + + if (result.GetProcessing() == JsonSerializationResult::Processing::Completed) + { + return context.Report(result, "Successfully stored property group."); + } + else + { + return context.Report(result, "Partially stored property group."); + } + } + + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp index b8b55a9fd5..4c66f753f2 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertySerializer.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -23,11 +24,12 @@ namespace AZ { namespace RPI { - namespace // Avoid conflicts in uber builds + namespace JsonMaterialPropertySerializerInternal { namespace Field { static constexpr const char name[] = "name"; + static constexpr const char id[] = "id"; // For backward compatibility static constexpr const char displayName[] = "displayName"; static constexpr const char description[] = "description"; static constexpr const char type[] = "type"; @@ -47,6 +49,7 @@ namespace AZ static const AZStd::string_view AcceptedFields[] = { Field::name, + Field::id, Field::displayName, Field::description, Field::type, @@ -103,6 +106,7 @@ namespace AZ JsonDeserializerContext& context) { namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertySerializerInternal; JSR::ResultCode result(JSR::Tasks::ReadField); @@ -160,6 +164,7 @@ namespace AZ JsonDeserializerContext& context) { namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertySerializerInternal; JSR::ResultCode result(JSR::Tasks::ReadField); @@ -181,6 +186,7 @@ namespace AZ const rapidjson::Value& inputValue, JsonDeserializerContext& context) { namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertySerializerInternal; AZ_Assert(azrtti_typeid() == outputValueTypeId, "Unable to deserialize material property to json because the provided type is %s", @@ -197,28 +203,19 @@ namespace AZ return context.Report(JsonSerializationResult::Tasks::ReadField, JsonSerializationResult::Outcomes::Unsupported, "Property definition must be a JSON object."); } - // First check for unexpected fields - for (auto iter = inputValue.MemberBegin(); iter != inputValue.MemberEnd(); ++iter) + MaterialUtils::CheckForUnrecognizedJsonFields(AcceptedFields, AZ_ARRAY_SIZE(AcceptedFields), inputValue, context, result); + + JsonSerializationResult::ResultCode nameResult = ContinueLoadingFromJsonObjectField(&property->m_name, azrtti_typeid(), inputValue, Field::name, context); + if (nameResult.GetOutcome() == JsonSerializationResult::Outcomes::DefaultsUsed) { - bool matched = false; - - for (int i = 0; i < AZ_ARRAY_SIZE(AcceptedFields); ++i) - { - if (iter->name.GetString() == AcceptedFields[i]) - { - matched = true; - break; - } - } - - if (!matched) - { - ScopedContextPath subPath{context, iter->name.GetString()}; - result.Combine(context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Skipped, "Skipping unrecognized field")); - } + // This "id" key is for backward compatibility. + result.Combine(ContinueLoadingFromJsonObjectField(&property->m_name, azrtti_typeid(), inputValue, Field::id, context)); + } + else + { + result.Combine(nameResult); } - result.Combine(ContinueLoadingFromJsonObjectField(&property->m_name, azrtti_typeid(), inputValue, Field::name, context)); result.Combine(ContinueLoadingFromJsonObjectField(&property->m_displayName, azrtti_typeid(), inputValue, Field::displayName, context)); result.Combine(ContinueLoadingFromJsonObjectField(&property->m_description, azrtti_typeid(), inputValue, Field::description, context)); result.Combine(ContinueLoadingFromJsonObjectField(&property->m_dataType, azrtti_typeid(), inputValue, Field::type, context)); @@ -302,6 +299,8 @@ namespace AZ JsonSerializerContext& context) { namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertySerializerInternal; + JSR::ResultCode result(JSR::Tasks::WriteValue); if (property->m_value.Is()) @@ -345,6 +344,8 @@ namespace AZ JsonSerializerContext& context) { namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertySerializerInternal; + JsonSerializationResult::ResultCode result(JSR::Tasks::WriteValue); if (property->m_value.Is()) @@ -360,6 +361,7 @@ namespace AZ [[maybe_unused]] const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) { namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertySerializerInternal; AZ_Assert(azrtti_typeid() == valueTypeId, "Unable to serialize material property to json because the provided type is %s", @@ -452,6 +454,8 @@ namespace AZ const rapidjson::Value& inputValue, JsonDeserializerContext& context) { namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertySerializerInternal; + JSR::ResultCode result(JSR::Tasks::ReadField); if (inputValue.HasMember(Field::vectorLabels)) @@ -467,6 +471,8 @@ namespace AZ { AZStd::string emptyString; namespace JSR = JsonSerializationResult; + using namespace JsonMaterialPropertySerializerInternal; + JsonSerializationResult::ResultCode result(JSR::Tasks::WriteValue); if (!property->m_vectorLabels.empty()) 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 a13a8df16e..1cc57f4d47 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -46,29 +48,17 @@ namespace AZ if (JsonRegistrationContext* jsonContext = azrtti_cast(context)) { jsonContext->Serializer()->HandlesType(); + jsonContext->Serializer()->HandlesType(); + jsonContext->Serializer()->HandlesType(); } else if (auto* serializeContext = azrtti_cast(context)) { - serializeContext->Class() - ->Version(2) - ->Field("type", &PropertyConnection::m_type) - ->Field("name", &PropertyConnection::m_fieldName) - ->Field("shaderIndex", &PropertyConnection::m_shaderIndex) - ; + serializeContext->Class()->Version(3); + serializeContext->Class()->Version(4); + serializeContext->Class()->Version(1); serializeContext->RegisterGenericType(); - serializeContext->Class() - ->Version(2) - ->Field("name", &GroupDefinition::m_name) - ->Field("displayName", &GroupDefinition::m_displayName) - ->Field("description", &GroupDefinition::m_description) - ; - - serializeContext->Class() - ->Version(1) - ; - serializeContext->Class() ->Version(2) ->Field("file", &ShaderVariantReferenceData::m_shaderFilePath) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialUtils.cpp index 62f4f02e3c..90ce9e66ce 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialUtils.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialUtils.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include @@ -99,6 +101,29 @@ namespace AZ return AZ::Success(AZStd::move(materialType)); } } + + void CheckForUnrecognizedJsonFields(const AZStd::string_view* acceptedFieldNames, uint32_t acceptedFieldNameCount, const rapidjson::Value& object, JsonDeserializerContext& context, JsonSerializationResult::ResultCode &result) + { + for (auto iter = object.MemberBegin(); iter != object.MemberEnd(); ++iter) + { + bool matched = false; + + for (uint32_t i = 0; i < acceptedFieldNameCount; ++i) + { + if (iter->name.GetString() == acceptedFieldNames[i]) + { + matched = true; + break; + } + } + + if (!matched) + { + ScopedContextPath subPath{context, iter->name.GetString()}; + result.Combine(context.Report(JsonSerializationResult::Tasks::ReadField, JsonSerializationResult::Outcomes::Skipped, "Skipping unrecognized field")); + } + } + } } } } diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp index 5705c3416a..9afc05a237 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp @@ -828,6 +828,41 @@ namespace UnitTest TestStoreToJson(propertyData, inputJson); } + + TEST_F(MaterialPropertySerializerTests, LoadUsingOldFormat) + { + // Tests backward compatibility for when "id" was the key instead of "name", for both the property and its connections. + + const AZStd::string inputJson = R"( + { + "id": "testProperty", + "type": "Float", + "connection": { + "type": "ShaderOption", + "id": "o_foo", + "shaderIndex": 2 + } + } + )"; + + MaterialTypeSourceData::PropertyDefinition propertyData; + JsonTestResult loadResult = LoadTestDataFromJson(propertyData, inputJson); + + EXPECT_EQ(AZ::JsonSerializationResult::Tasks::ReadField, loadResult.m_jsonResultCode.GetTask()); + EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, loadResult.m_jsonResultCode.GetProcessing()); + + EXPECT_EQ("testProperty", propertyData.m_name); + + EXPECT_EQ(1, propertyData.m_outputConnections.size()); + EXPECT_EQ(MaterialPropertyOutputType::ShaderOption, propertyData.m_outputConnections[0].m_type); + EXPECT_EQ("o_foo", propertyData.m_outputConnections[0].m_fieldName); + EXPECT_EQ(2, propertyData.m_outputConnections[0].m_shaderIndex); + + EXPECT_TRUE(loadResult.ContainsMessage("/connection/type", "Success")); + EXPECT_TRUE(loadResult.ContainsMessage("/connection/id", "Success")); + EXPECT_TRUE(loadResult.ContainsMessage("/connection/shaderIndex", "Success")); + EXPECT_FALSE(loadResult.ContainsOutcome(JsonSerializationResult::Outcomes::Skipped)); + } TEST_F(MaterialPropertySerializerTests, LoadAndStoreJson_MultipleConnections) { diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp index c37943f79c..ba4a58b9ff 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp @@ -1115,6 +1115,148 @@ namespace UnitTest JsonTestResult storeResult = StoreTestDataToJson(material, outputJson); ExpectSimilarJson(inputJson, outputJson); } + + TEST_F(MaterialTypeSourceDataTests, LoadAllFieldsUsingOldFormat) + { + // The content of this test was copied from LoadAndStoreJson_AllFields to prove backward compatibility. + // (The "store" part of the test was not included because the saved data will be the new format). + + const AZStd::string inputJson = R"( + { + "description": "This is a general description about the material", + "propertyLayout": { + "version": 2, + "groups": [ + { + "id": "groupA", + "displayName": "Property Group A", + "description": "Description of property group A" + }, + { + "id": "groupB", + "displayName": "Property Group B", + "description": "Description of property group B" + } + ], + "properties": { + "groupA": [ + { + "id": "foo", + "type": "Bool", + "defaultValue": true + }, + { + "id": "bar", + "type": "Image", + "defaultValue": "Default.png", + "visibility": "Hidden" + } + ], + "groupB": [ + { + "id": "foo", + "type": "Float", + "defaultValue": 0.5 + }, + { + "id": "bar", + "type": "Color", + "defaultValue": [0.5, 0.5, 0.5], + "visibility": "Disabled" + } + ] + } + }, + "shaders": [ + { + "file": "ForwardPass.shader", + "tag": "ForwardPass", + "options": { + "o_optionA": "False", + "o_optionB": "True" + } + }, + { + "file": "DepthPass.shader", + "options": { + "o_optionC": "1", + "o_optionD": "2" + } + } + ], + "functors": [ + { + "type": "EnableShader", + "args": { + "enablePassProperty": "groupA.foo", + "shaderIndex": 1 + } + }, + { + "type": "Splat3", + "args": { + "floatPropertyInput": "groupB.foo", + "float3ShaderSettingOutput": "m_someFloat3" + } + } + ] + } + )"; + + MaterialTypeSourceData material; + JsonTestResult loadResult = LoadTestDataFromJson(material, inputJson); + + EXPECT_EQ(material.m_description, "This is a general description about the material"); + + EXPECT_EQ(material.m_propertyLayout.m_version, 2); + + EXPECT_EQ(material.m_propertyLayout.m_groups.size(), 2); + EXPECT_TRUE(material.FindGroup("groupA") != nullptr); + EXPECT_TRUE(material.FindGroup("groupB") != nullptr); + EXPECT_EQ(material.FindGroup("groupA")->m_displayName, "Property Group A"); + EXPECT_EQ(material.FindGroup("groupB")->m_displayName, "Property Group B"); + EXPECT_EQ(material.FindGroup("groupA")->m_description, "Description of property group A"); + EXPECT_EQ(material.FindGroup("groupB")->m_description, "Description of property group B"); + + EXPECT_EQ(material.m_propertyLayout.m_properties.size(), 2); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"].size(), 2); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"].size(), 2); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_name, "foo"); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_name, "bar"); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_name, "foo"); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_name, "bar"); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_dataType, MaterialPropertyDataType::Bool); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_dataType, MaterialPropertyDataType::Image); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_dataType, MaterialPropertyDataType::Float); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_dataType, MaterialPropertyDataType::Color); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_visibility, MaterialPropertyVisibility::Enabled); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_visibility, MaterialPropertyVisibility::Hidden); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_visibility, MaterialPropertyVisibility::Enabled); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_visibility, MaterialPropertyVisibility::Disabled); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_value, true); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_value, AZStd::string{"Default.png"}); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_value, 0.5f); + EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_value, AZ::Color(0.5f, 0.5f, 0.5f, 1.0f)); + + EXPECT_EQ(material.m_shaderCollection.size(), 2); + EXPECT_EQ(material.m_shaderCollection[0].m_shaderFilePath, "ForwardPass.shader"); + EXPECT_EQ(material.m_shaderCollection[1].m_shaderFilePath, "DepthPass.shader"); + EXPECT_EQ(material.m_shaderCollection[0].m_shaderOptionValues.size(), 2); + EXPECT_EQ(material.m_shaderCollection[1].m_shaderOptionValues.size(), 2); + EXPECT_EQ(material.m_shaderCollection[0].m_shaderOptionValues[Name{"o_optionA"}], Name{"False"}); + EXPECT_EQ(material.m_shaderCollection[0].m_shaderOptionValues[Name{"o_optionB"}], Name{"True"}); + EXPECT_EQ(material.m_shaderCollection[1].m_shaderOptionValues[Name{"o_optionC"}], Name{"1"}); + EXPECT_EQ(material.m_shaderCollection[1].m_shaderOptionValues[Name{"o_optionD"}], Name{"2"}); + EXPECT_EQ(material.m_shaderCollection[0].m_shaderTag, Name{"ForwardPass"}); + + EXPECT_EQ(material.m_materialFunctorSourceData.size(), 2); + EXPECT_TRUE(azrtti_cast(material.m_materialFunctorSourceData[0]->GetActualSourceData().get())); + EXPECT_EQ(azrtti_cast(material.m_materialFunctorSourceData[0]->GetActualSourceData().get())->m_enablePassPropertyId, "groupA.foo"); + EXPECT_EQ(azrtti_cast(material.m_materialFunctorSourceData[0]->GetActualSourceData().get())->m_shaderIndex, 1); + EXPECT_TRUE(azrtti_cast(material.m_materialFunctorSourceData[1]->GetActualSourceData().get())); + EXPECT_EQ(azrtti_cast(material.m_materialFunctorSourceData[1]->GetActualSourceData().get())->m_floatPropertyInputId, "groupB.foo"); + EXPECT_EQ(azrtti_cast(material.m_materialFunctorSourceData[1]->GetActualSourceData().get())->m_float3ShaderSettingOutputId, "m_someFloat3"); + } TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_PropertyImagePath) { diff --git a/Gems/Atom/RPI/Code/atom_rpi_edit_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_edit_files.cmake index c7a459f217..e32d19ffd7 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_edit_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_edit_files.cmake @@ -18,6 +18,8 @@ set(FILES Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h Include/Atom/RPI.Edit/Material/MaterialConverterBus.h Include/Atom/RPI.Edit/Material/MaterialPropertyId.h + Include/Atom/RPI.Edit/Material/MaterialPropertyConnectionSerializer.h + Include/Atom/RPI.Edit/Material/MaterialPropertyGroupSerializer.h Include/Atom/RPI.Edit/Material/MaterialPropertySerializer.h Include/Atom/RPI.Edit/Material/MaterialPropertyValueSerializer.h Include/Atom/RPI.Edit/Material/MaterialPropertyValueSourceData.h @@ -36,6 +38,8 @@ set(FILES Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp Source/RPI.Edit/Material/MaterialTypeSourceData.cpp Source/RPI.Edit/Material/MaterialPropertyId.cpp + Source/RPI.Edit/Material/MaterialPropertyGroupSerializer.cpp + Source/RPI.Edit/Material/MaterialPropertyConnectionSerializer.cpp Source/RPI.Edit/Material/MaterialPropertySerializer.cpp Source/RPI.Edit/Material/MaterialPropertyValueSerializer.cpp Source/RPI.Edit/Material/MaterialPropertyValueSourceData.cpp From b28f871b2007ef71baf71481270562c1198f5bcf Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 28 Sep 2021 23:32:15 -0700 Subject: [PATCH 065/115] Fix casing of BreadCrumbs include in PrefabViewportFocusPathHandler. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h index f1d09311da..ce7744fb1b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h @@ -12,7 +12,7 @@ #include -#include +#include #include #include From c34b6ffe3bc302cce3fa814da40518a08c5a3638 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Wed, 29 Sep 2021 10:11:49 +0100 Subject: [PATCH 066/115] Overhaul of how camera orbit/pivot behavior works (#4345) * overhaul to how camera orbit/pivot behavior works Signed-off-by: hultonha * update naming from orbit to pivot Signed-off-by: hultonha * fix camera unit tests Signed-off-by: hultonha * add additional tests for new camera pivot behavior Signed-off-by: hultonha * fix comment and add additional info for tests Signed-off-by: hultonha --- .../EditorModularViewportCameraComposer.cpp | 105 +++++------ .../EditorModularViewportCameraComposer.h | 12 +- .../EditorPreferencesPageViewportCamera.cpp | 54 +++--- .../EditorPreferencesPageViewportCamera.h | 10 +- Code/Editor/EditorViewportSettings.cpp | 50 ++--- Code/Editor/EditorViewportSettings.h | 20 +- .../AzFramework/Viewport/CameraInput.cpp | 175 +++++++----------- .../AzFramework/Viewport/CameraInput.h | 121 ++++++++---- .../AzFramework/Tests/CameraInputTests.cpp | 163 +++++++++++++--- .../ModularViewportCameraController.h | 5 - .../ModularViewportCameraController.cpp | 29 +-- 11 files changed, 410 insertions(+), 334 deletions(-) diff --git a/Code/Editor/EditorModularViewportCameraComposer.cpp b/Code/Editor/EditorModularViewportCameraComposer.cpp index e375e98fb6..600f2089e6 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.cpp +++ b/Code/Editor/EditorModularViewportCameraComposer.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace SandboxEditor @@ -94,7 +95,7 @@ namespace SandboxEditor cameras.AddCamera(m_firstPersonPanCamera); cameras.AddCamera(m_firstPersonTranslateCamera); cameras.AddCamera(m_firstPersonScrollCamera); - cameras.AddCamera(m_orbitCamera); + cameras.AddCamera(m_pivotCamera); }); return controller; @@ -131,8 +132,8 @@ namespace SandboxEditor m_firstPersonRotateCamera->SetActivationBeganFn(hideCursor); m_firstPersonRotateCamera->SetActivationEndedFn(showCursor); - m_firstPersonPanCamera = - AZStd::make_shared(SandboxEditor::CameraFreePanChannelId(), AzFramework::LookPan); + m_firstPersonPanCamera = AZStd::make_shared( + SandboxEditor::CameraFreePanChannelId(), AzFramework::LookPan, AzFramework::TranslatePivot); m_firstPersonPanCamera->m_panSpeedFn = [] { @@ -151,8 +152,8 @@ namespace SandboxEditor const auto translateCameraInputChannelIds = BuildTranslateCameraInputChannelIds(); - m_firstPersonTranslateCamera = - AZStd::make_shared(AzFramework::LookTranslation, translateCameraInputChannelIds); + m_firstPersonTranslateCamera = AZStd::make_shared( + translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivot); m_firstPersonTranslateCamera->m_translateSpeedFn = [] { @@ -171,10 +172,10 @@ namespace SandboxEditor return SandboxEditor::CameraScrollSpeed(); }; - m_orbitCamera = AZStd::make_shared(SandboxEditor::CameraOrbitChannelId()); + m_pivotCamera = AZStd::make_shared(SandboxEditor::CameraPivotChannelId()); - m_orbitCamera->SetLookAtFn( - [viewportId = m_viewportId](const AZ::Vector3& position, const AZ::Vector3& direction) -> AZStd::optional + m_pivotCamera->SetPivotFn( + [viewportId = m_viewportId]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) { AZStd::optional lookAtAfterInterpolation; AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult( @@ -182,109 +183,98 @@ namespace SandboxEditor &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::LookAtAfterInterpolation); // initially attempt to use the last set look at point after an interpolation has finished - if (lookAtAfterInterpolation.has_value()) + // note: ignore this if it is the same location as the camera (e.g. after go to position) + if (lookAtAfterInterpolation.has_value() && !lookAtAfterInterpolation->IsClose(position)) { return *lookAtAfterInterpolation; } - const float RayDistance = 1000.0f; - AzFramework::RenderGeometry::RayRequest ray; - ray.m_startWorldPosition = position; - ray.m_endWorldPosition = position + direction * RayDistance; - ray.m_onlyVisible = true; + // otherwise fall back to the selected entity pivot + AZStd::optional entityPivot; + AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( + entityPivot, AzToolsFramework::GetEntityContextId(), + &AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform); - AzFramework::RenderGeometry::RayResult renderGeometryIntersectionResult; - AzFramework::RenderGeometry::IntersectorBus::EventResult( - renderGeometryIntersectionResult, AzToolsFramework::GetEntityContextId(), - &AzFramework::RenderGeometry::IntersectorBus::Events::RayIntersect, ray); - - // attempt a ray intersection with any visible mesh and return the intersection position if successful - if (renderGeometryIntersectionResult) - { - return renderGeometryIntersectionResult.m_worldPosition; - } - - // if there is no selection or no intersection, fallback to default camera orbit behavior (ground plane - // intersection) - return {}; + // finally just use the identity + return entityPivot.value_or(AZ::Transform::CreateIdentity()).GetTranslation(); }); - m_orbitRotateCamera = AZStd::make_shared(SandboxEditor::CameraOrbitLookChannelId()); + m_pivotRotateCamera = AZStd::make_shared(SandboxEditor::CameraPivotLookChannelId()); - m_orbitRotateCamera->m_rotateSpeedFn = [] + m_pivotRotateCamera->m_rotateSpeedFn = [] { return SandboxEditor::CameraRotateSpeed(); }; - m_orbitRotateCamera->m_invertYawFn = [] + m_pivotRotateCamera->m_invertYawFn = [] { - return SandboxEditor::CameraOrbitYawRotationInverted(); + return SandboxEditor::CameraPivotYawRotationInverted(); }; - m_orbitTranslateCamera = - AZStd::make_shared(AzFramework::OrbitTranslation, translateCameraInputChannelIds); + m_pivotTranslateCamera = AZStd::make_shared( + translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslateOffset); - m_orbitTranslateCamera->m_translateSpeedFn = [] + m_pivotTranslateCamera->m_translateSpeedFn = [] { return SandboxEditor::CameraTranslateSpeed(); }; - m_orbitTranslateCamera->m_boostMultiplierFn = [] + m_pivotTranslateCamera->m_boostMultiplierFn = [] { return SandboxEditor::CameraBoostMultiplier(); }; - m_orbitDollyScrollCamera = AZStd::make_shared(); + m_pivotDollyScrollCamera = AZStd::make_shared(); - m_orbitDollyScrollCamera->m_scrollSpeedFn = [] + m_pivotDollyScrollCamera->m_scrollSpeedFn = [] { return SandboxEditor::CameraScrollSpeed(); }; - m_orbitDollyMoveCamera = - AZStd::make_shared(SandboxEditor::CameraOrbitDollyChannelId()); + m_pivotDollyMoveCamera = AZStd::make_shared(SandboxEditor::CameraPivotDollyChannelId()); - m_orbitDollyMoveCamera->m_cursorSpeedFn = [] + m_pivotDollyMoveCamera->m_motionSpeedFn = [] { return SandboxEditor::CameraDollyMotionSpeed(); }; - m_orbitPanCamera = AZStd::make_shared(SandboxEditor::CameraOrbitPanChannelId(), AzFramework::OrbitPan); + m_pivotPanCamera = AZStd::make_shared( + SandboxEditor::CameraPivotPanChannelId(), AzFramework::LookPan, AzFramework::TranslateOffset); - m_orbitPanCamera->m_panSpeedFn = [] + m_pivotPanCamera->m_panSpeedFn = [] { return SandboxEditor::CameraPanSpeed(); }; - m_orbitPanCamera->m_invertPanXFn = [] + m_pivotPanCamera->m_invertPanXFn = [] { return SandboxEditor::CameraPanInvertedX(); }; - m_orbitPanCamera->m_invertPanYFn = [] + m_pivotPanCamera->m_invertPanYFn = [] { return SandboxEditor::CameraPanInvertedY(); }; - m_orbitCamera->m_orbitCameras.AddCamera(m_orbitRotateCamera); - m_orbitCamera->m_orbitCameras.AddCamera(m_orbitTranslateCamera); - m_orbitCamera->m_orbitCameras.AddCamera(m_orbitDollyScrollCamera); - m_orbitCamera->m_orbitCameras.AddCamera(m_orbitDollyMoveCamera); - m_orbitCamera->m_orbitCameras.AddCamera(m_orbitPanCamera); + m_pivotCamera->m_pivotCameras.AddCamera(m_pivotRotateCamera); + m_pivotCamera->m_pivotCameras.AddCamera(m_pivotTranslateCamera); + m_pivotCamera->m_pivotCameras.AddCamera(m_pivotDollyScrollCamera); + m_pivotCamera->m_pivotCameras.AddCamera(m_pivotDollyMoveCamera); + m_pivotCamera->m_pivotCameras.AddCamera(m_pivotPanCamera); } void EditorModularViewportCameraComposer::OnEditorModularViewportCameraComposerSettingsChanged() { const auto translateCameraInputChannelIds = BuildTranslateCameraInputChannelIds(); m_firstPersonTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds); - m_orbitTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds); - m_firstPersonPanCamera->SetPanInputChannelId(SandboxEditor::CameraFreePanChannelId()); - m_orbitPanCamera->SetPanInputChannelId(SandboxEditor::CameraOrbitPanChannelId()); m_firstPersonRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraFreeLookChannelId()); - m_orbitRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraOrbitLookChannelId()); - m_orbitCamera->SetOrbitInputChannelId(SandboxEditor::CameraOrbitChannelId()); - m_orbitDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraOrbitDollyChannelId()); + + m_pivotCamera->SetPivotInputChannelId(SandboxEditor::CameraPivotChannelId()); + m_pivotTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds); + m_pivotPanCamera->SetPanInputChannelId(SandboxEditor::CameraPivotPanChannelId()); + m_pivotRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraPivotLookChannelId()); + m_pivotDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraPivotDollyChannelId()); } void EditorModularViewportCameraComposer::OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId) @@ -295,8 +285,7 @@ namespace SandboxEditor AZ::TransformBus::EventResult(worldFromLocal, viewEntityId, &AZ::TransformBus::Events::GetWorldTM); AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( - m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, - worldFromLocal); + m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, worldFromLocal); } else { diff --git a/Code/Editor/EditorModularViewportCameraComposer.h b/Code/Editor/EditorModularViewportCameraComposer.h index e6e71c976c..e691ca1c89 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.h +++ b/Code/Editor/EditorModularViewportCameraComposer.h @@ -42,12 +42,12 @@ namespace SandboxEditor AZStd::shared_ptr m_firstPersonPanCamera; AZStd::shared_ptr m_firstPersonTranslateCamera; AZStd::shared_ptr m_firstPersonScrollCamera; - AZStd::shared_ptr m_orbitCamera; - AZStd::shared_ptr m_orbitRotateCamera; - AZStd::shared_ptr m_orbitTranslateCamera; - AZStd::shared_ptr m_orbitDollyScrollCamera; - AZStd::shared_ptr m_orbitDollyMoveCamera; - AZStd::shared_ptr m_orbitPanCamera; + AZStd::shared_ptr m_pivotCamera; + AZStd::shared_ptr m_pivotRotateCamera; + AZStd::shared_ptr m_pivotTranslateCamera; + AZStd::shared_ptr m_pivotDollyScrollCamera; + AZStd::shared_ptr m_pivotDollyMoveCamera; + AZStd::shared_ptr m_pivotPanCamera; AzFramework::ViewportId m_viewportId; }; diff --git a/Code/Editor/EditorPreferencesPageViewportCamera.cpp b/Code/Editor/EditorPreferencesPageViewportCamera.cpp index 368d2769f8..55b631e1f6 100644 --- a/Code/Editor/EditorPreferencesPageViewportCamera.cpp +++ b/Code/Editor/EditorPreferencesPageViewportCamera.cpp @@ -61,7 +61,7 @@ static AZStd::vector GetEditorInputNames() void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serialize) { serialize.Class() - ->Version(2) + ->Version(3) ->Field("TranslateSpeed", &CameraMovementSettings::m_translateSpeed) ->Field("RotateSpeed", &CameraMovementSettings::m_rotateSpeed) ->Field("BoostMultiplier", &CameraMovementSettings::m_boostMultiplier) @@ -73,12 +73,12 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial ->Field("TranslateSmoothing", &CameraMovementSettings::m_translateSmoothing) ->Field("TranslateSmoothness", &CameraMovementSettings::m_translateSmoothness) ->Field("CaptureCursorLook", &CameraMovementSettings::m_captureCursorLook) - ->Field("OrbitYawRotationInverted", &CameraMovementSettings::m_orbitYawRotationInverted) + ->Field("PivotYawRotationInverted", &CameraMovementSettings::m_pivotYawRotationInverted) ->Field("PanInvertedX", &CameraMovementSettings::m_panInvertedX) ->Field("PanInvertedY", &CameraMovementSettings::m_panInvertedY); serialize.Class() - ->Version(1) + ->Version(2) ->Field("TranslateForward", &CameraInputSettings::m_translateForwardChannelId) ->Field("TranslateBackward", &CameraInputSettings::m_translateBackwardChannelId) ->Field("TranslateLeft", &CameraInputSettings::m_translateLeftChannelId) @@ -86,12 +86,12 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial ->Field("TranslateUp", &CameraInputSettings::m_translateUpChannelId) ->Field("TranslateDown", &CameraInputSettings::m_translateDownChannelId) ->Field("Boost", &CameraInputSettings::m_boostChannelId) - ->Field("Orbit", &CameraInputSettings::m_orbitChannelId) + ->Field("Pivot", &CameraInputSettings::m_pivotChannelId) ->Field("FreeLook", &CameraInputSettings::m_freeLookChannelId) ->Field("FreePan", &CameraInputSettings::m_freePanChannelId) - ->Field("OrbitLook", &CameraInputSettings::m_orbitLookChannelId) - ->Field("OrbitDolly", &CameraInputSettings::m_orbitDollyChannelId) - ->Field("OrbitPan", &CameraInputSettings::m_orbitPanChannelId); + ->Field("PivotLook", &CameraInputSettings::m_pivotLookChannelId) + ->Field("PivotDolly", &CameraInputSettings::m_pivotDollyChannelId) + ->Field("PivotPan", &CameraInputSettings::m_pivotPanChannelId); serialize.Class() ->Version(1) @@ -143,8 +143,8 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial ->Attribute(AZ::Edit::Attributes::Min, minValue) ->Attribute(AZ::Edit::Attributes::Visibility, &CameraMovementSettings::TranslateSmoothingVisibility) ->DataElement( - AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_orbitYawRotationInverted, "Camera Orbit Yaw Inverted", - "Inverted yaw rotation while orbiting") + AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_pivotYawRotationInverted, "Camera Pivot Yaw Inverted", + "Inverted yaw rotation while pivoting") ->DataElement( AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_panInvertedX, "Invert Pan X", "Invert direction of pan in local X axis") @@ -185,8 +185,8 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial "Key/button to move the camera more quickly") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( - AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitChannelId, "Orbit", - "Key/button to begin the camera orbit behavior") + AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotChannelId, "Pivot", + "Key/button to begin the camera pivot behavior") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_freeLookChannelId, "Free Look", @@ -196,16 +196,16 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_freePanChannelId, "Free Pan", "Key/button to begin camera free pan") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( - AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitLookChannelId, "Orbit Look", - "Key/button to begin camera orbit look") + AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotLookChannelId, "Pivot Look", + "Key/button to begin camera pivot look") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( - AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitDollyChannelId, "Orbit Dolly", - "Key/button to begin camera orbit dolly") + AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotDollyChannelId, "Pivot Dolly", + "Key/button to begin camera pivot dolly") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( - AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitPanChannelId, "Orbit Pan", - "Key/button to begin camera orbit pan") + AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotPanChannelId, "Pivot Pan", + "Key/button to begin camera pivot pan") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames); editContext->Class("Viewport Preferences", "Viewport Preferences") @@ -264,7 +264,7 @@ void CEditorPreferencesPage_ViewportCamera::OnApply() SandboxEditor::SetCameraTranslateSmoothness(m_cameraMovementSettings.m_translateSmoothness); SandboxEditor::SetCameraTranslateSmoothingEnabled(m_cameraMovementSettings.m_translateSmoothing); SandboxEditor::SetCameraCaptureCursorForLook(m_cameraMovementSettings.m_captureCursorLook); - SandboxEditor::SetCameraOrbitYawRotationInverted(m_cameraMovementSettings.m_orbitYawRotationInverted); + SandboxEditor::SetCameraPivotYawRotationInverted(m_cameraMovementSettings.m_pivotYawRotationInverted); SandboxEditor::SetCameraPanInvertedX(m_cameraMovementSettings.m_panInvertedX); SandboxEditor::SetCameraPanInvertedY(m_cameraMovementSettings.m_panInvertedY); @@ -275,12 +275,12 @@ void CEditorPreferencesPage_ViewportCamera::OnApply() SandboxEditor::SetCameraTranslateUpChannelId(m_cameraInputSettings.m_translateUpChannelId); SandboxEditor::SetCameraTranslateDownChannelId(m_cameraInputSettings.m_translateDownChannelId); SandboxEditor::SetCameraTranslateBoostChannelId(m_cameraInputSettings.m_boostChannelId); - SandboxEditor::SetCameraOrbitChannelId(m_cameraInputSettings.m_orbitChannelId); + SandboxEditor::SetCameraPivotChannelId(m_cameraInputSettings.m_pivotChannelId); SandboxEditor::SetCameraFreeLookChannelId(m_cameraInputSettings.m_freeLookChannelId); SandboxEditor::SetCameraFreePanChannelId(m_cameraInputSettings.m_freePanChannelId); - SandboxEditor::SetCameraOrbitLookChannelId(m_cameraInputSettings.m_orbitLookChannelId); - SandboxEditor::SetCameraOrbitDollyChannelId(m_cameraInputSettings.m_orbitDollyChannelId); - SandboxEditor::SetCameraOrbitPanChannelId(m_cameraInputSettings.m_orbitPanChannelId); + SandboxEditor::SetCameraPivotLookChannelId(m_cameraInputSettings.m_pivotLookChannelId); + SandboxEditor::SetCameraPivotDollyChannelId(m_cameraInputSettings.m_pivotDollyChannelId); + SandboxEditor::SetCameraPivotPanChannelId(m_cameraInputSettings.m_pivotPanChannelId); SandboxEditor::EditorModularViewportCameraComposerNotificationBus::Broadcast( &SandboxEditor::EditorModularViewportCameraComposerNotificationBus::Events::OnEditorModularViewportCameraComposerSettingsChanged); @@ -299,7 +299,7 @@ void CEditorPreferencesPage_ViewportCamera::InitializeSettings() m_cameraMovementSettings.m_translateSmoothness = SandboxEditor::CameraTranslateSmoothness(); m_cameraMovementSettings.m_translateSmoothing = SandboxEditor::CameraTranslateSmoothingEnabled(); m_cameraMovementSettings.m_captureCursorLook = SandboxEditor::CameraCaptureCursorForLook(); - m_cameraMovementSettings.m_orbitYawRotationInverted = SandboxEditor::CameraOrbitYawRotationInverted(); + m_cameraMovementSettings.m_pivotYawRotationInverted = SandboxEditor::CameraPivotYawRotationInverted(); m_cameraMovementSettings.m_panInvertedX = SandboxEditor::CameraPanInvertedX(); m_cameraMovementSettings.m_panInvertedY = SandboxEditor::CameraPanInvertedY(); @@ -310,10 +310,10 @@ void CEditorPreferencesPage_ViewportCamera::InitializeSettings() m_cameraInputSettings.m_translateUpChannelId = SandboxEditor::CameraTranslateUpChannelId().GetName(); m_cameraInputSettings.m_translateDownChannelId = SandboxEditor::CameraTranslateDownChannelId().GetName(); m_cameraInputSettings.m_boostChannelId = SandboxEditor::CameraTranslateBoostChannelId().GetName(); - m_cameraInputSettings.m_orbitChannelId = SandboxEditor::CameraOrbitChannelId().GetName(); + m_cameraInputSettings.m_pivotChannelId = SandboxEditor::CameraPivotChannelId().GetName(); m_cameraInputSettings.m_freeLookChannelId = SandboxEditor::CameraFreeLookChannelId().GetName(); m_cameraInputSettings.m_freePanChannelId = SandboxEditor::CameraFreePanChannelId().GetName(); - m_cameraInputSettings.m_orbitLookChannelId = SandboxEditor::CameraOrbitLookChannelId().GetName(); - m_cameraInputSettings.m_orbitDollyChannelId = SandboxEditor::CameraOrbitDollyChannelId().GetName(); - m_cameraInputSettings.m_orbitPanChannelId = SandboxEditor::CameraOrbitPanChannelId().GetName(); + m_cameraInputSettings.m_pivotLookChannelId = SandboxEditor::CameraPivotLookChannelId().GetName(); + m_cameraInputSettings.m_pivotDollyChannelId = SandboxEditor::CameraPivotDollyChannelId().GetName(); + m_cameraInputSettings.m_pivotPanChannelId = SandboxEditor::CameraPivotPanChannelId().GetName(); } diff --git a/Code/Editor/EditorPreferencesPageViewportCamera.h b/Code/Editor/EditorPreferencesPageViewportCamera.h index 31a728599f..01dc4664f6 100644 --- a/Code/Editor/EditorPreferencesPageViewportCamera.h +++ b/Code/Editor/EditorPreferencesPageViewportCamera.h @@ -54,7 +54,7 @@ private: float m_translateSmoothness; bool m_translateSmoothing; bool m_captureCursorLook; - bool m_orbitYawRotationInverted; + bool m_pivotYawRotationInverted; bool m_panInvertedX; bool m_panInvertedY; @@ -80,12 +80,12 @@ private: AZStd::string m_translateUpChannelId; AZStd::string m_translateDownChannelId; AZStd::string m_boostChannelId; - AZStd::string m_orbitChannelId; + AZStd::string m_pivotChannelId; AZStd::string m_freeLookChannelId; AZStd::string m_freePanChannelId; - AZStd::string m_orbitLookChannelId; - AZStd::string m_orbitDollyChannelId; - AZStd::string m_orbitPanChannelId; + AZStd::string m_pivotLookChannelId; + AZStd::string m_pivotDollyChannelId; + AZStd::string m_pivotPanChannelId; }; CameraMovementSettings m_cameraMovementSettings; diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp index 063ec125ba..fe8efecd17 100644 --- a/Code/Editor/EditorViewportSettings.cpp +++ b/Code/Editor/EditorViewportSettings.cpp @@ -28,7 +28,7 @@ namespace SandboxEditor constexpr AZStd::string_view CameraRotateSpeedSetting = "/Amazon/Preferences/Editor/Camera/RotateSpeed"; constexpr AZStd::string_view CameraScrollSpeedSetting = "/Amazon/Preferences/Editor/Camera/DollyScrollSpeed"; constexpr AZStd::string_view CameraDollyMotionSpeedSetting = "/Amazon/Preferences/Editor/Camera/DollyMotionSpeed"; - constexpr AZStd::string_view CameraOrbitYawRotationInvertedSetting = "/Amazon/Preferences/Editor/Camera/YawRotationInverted"; + constexpr AZStd::string_view CameraPivotYawRotationInvertedSetting = "/Amazon/Preferences/Editor/Camera/YawRotationInverted"; constexpr AZStd::string_view CameraPanInvertedXSetting = "/Amazon/Preferences/Editor/Camera/PanInvertedX"; constexpr AZStd::string_view CameraPanInvertedYSetting = "/Amazon/Preferences/Editor/Camera/PanInvertedY"; constexpr AZStd::string_view CameraPanSpeedSetting = "/Amazon/Preferences/Editor/Camera/PanSpeed"; @@ -44,12 +44,12 @@ namespace SandboxEditor constexpr AZStd::string_view CameraTranslateUpIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpId"; constexpr AZStd::string_view CameraTranslateDownIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpDownId"; constexpr AZStd::string_view CameraTranslateBoostIdSetting = "/Amazon/Preferences/Editor/Camera/TranslateBoostId"; - constexpr AZStd::string_view CameraOrbitIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitId"; + constexpr AZStd::string_view CameraPivotIdSetting = "/Amazon/Preferences/Editor/Camera/PivotId"; constexpr AZStd::string_view CameraFreeLookIdSetting = "/Amazon/Preferences/Editor/Camera/FreeLookId"; constexpr AZStd::string_view CameraFreePanIdSetting = "/Amazon/Preferences/Editor/Camera/FreePanId"; - constexpr AZStd::string_view CameraOrbitLookIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitLookId"; - constexpr AZStd::string_view CameraOrbitDollyIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitDollyId"; - constexpr AZStd::string_view CameraOrbitPanIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitPanId"; + constexpr AZStd::string_view CameraPivotLookIdSetting = "/Amazon/Preferences/Editor/Camera/PivotLookId"; + constexpr AZStd::string_view CameraPivotDollyIdSetting = "/Amazon/Preferences/Editor/Camera/PivotDollyId"; + constexpr AZStd::string_view CameraPivotPanIdSetting = "/Amazon/Preferences/Editor/Camera/PivotPanId"; template void SetRegistry(const AZStd::string_view setting, T&& value) @@ -239,14 +239,14 @@ namespace SandboxEditor SetRegistry(CameraDollyMotionSpeedSetting, speed); } - bool CameraOrbitYawRotationInverted() + bool CameraPivotYawRotationInverted() { - return GetRegistry(CameraOrbitYawRotationInvertedSetting, false); + return GetRegistry(CameraPivotYawRotationInvertedSetting, false); } - void SetCameraOrbitYawRotationInverted(const bool inverted) + void SetCameraPivotYawRotationInverted(const bool inverted) { - SetRegistry(CameraOrbitYawRotationInvertedSetting, inverted); + SetRegistry(CameraPivotYawRotationInvertedSetting, inverted); } bool CameraPanInvertedX() @@ -403,14 +403,14 @@ namespace SandboxEditor SetRegistry(CameraTranslateBoostIdSetting, cameraTranslateBoostId); } - AzFramework::InputChannelId CameraOrbitChannelId() + AzFramework::InputChannelId CameraPivotChannelId() { - return AzFramework::InputChannelId(GetRegistry(CameraOrbitIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str()); + return AzFramework::InputChannelId(GetRegistry(CameraPivotIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str()); } - void SetCameraOrbitChannelId(AZStd::string_view cameraOrbitId) + void SetCameraPivotChannelId(AZStd::string_view cameraPivotId) { - SetRegistry(CameraOrbitIdSetting, cameraOrbitId); + SetRegistry(CameraPivotIdSetting, cameraPivotId); } AzFramework::InputChannelId CameraFreeLookChannelId() @@ -433,33 +433,33 @@ namespace SandboxEditor SetRegistry(CameraFreePanIdSetting, cameraFreePanId); } - AzFramework::InputChannelId CameraOrbitLookChannelId() + AzFramework::InputChannelId CameraPivotLookChannelId() { - return AzFramework::InputChannelId(GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str()); + return AzFramework::InputChannelId(GetRegistry(CameraPivotLookIdSetting, AZStd::string("mouse_button_left")).c_str()); } - void SetCameraOrbitLookChannelId(AZStd::string_view cameraOrbitLookId) + void SetCameraPivotLookChannelId(AZStd::string_view cameraPivotLookId) { - SetRegistry(CameraOrbitLookIdSetting, cameraOrbitLookId); + SetRegistry(CameraPivotLookIdSetting, cameraPivotLookId); } - AzFramework::InputChannelId CameraOrbitDollyChannelId() + AzFramework::InputChannelId CameraPivotDollyChannelId() { - return AzFramework::InputChannelId(GetRegistry(CameraOrbitDollyIdSetting, AZStd::string("mouse_button_right")).c_str()); + return AzFramework::InputChannelId(GetRegistry(CameraPivotDollyIdSetting, AZStd::string("mouse_button_right")).c_str()); } - void SetCameraOrbitDollyChannelId(AZStd::string_view cameraOrbitDollyId) + void SetCameraPivotDollyChannelId(AZStd::string_view cameraPivotDollyId) { - SetRegistry(CameraOrbitDollyIdSetting, cameraOrbitDollyId); + SetRegistry(CameraPivotDollyIdSetting, cameraPivotDollyId); } - AzFramework::InputChannelId CameraOrbitPanChannelId() + AzFramework::InputChannelId CameraPivotPanChannelId() { - return AzFramework::InputChannelId(GetRegistry(CameraOrbitPanIdSetting, AZStd::string("mouse_button_middle")).c_str()); + return AzFramework::InputChannelId(GetRegistry(CameraPivotPanIdSetting, AZStd::string("mouse_button_middle")).c_str()); } - void SetCameraOrbitPanChannelId(AZStd::string_view cameraOrbitPanId) + void SetCameraPivotPanChannelId(AZStd::string_view cameraPivotPanId) { - SetRegistry(CameraOrbitPanIdSetting, cameraOrbitPanId); + SetRegistry(CameraPivotPanIdSetting, cameraPivotPanId); } } // namespace SandboxEditor diff --git a/Code/Editor/EditorViewportSettings.h b/Code/Editor/EditorViewportSettings.h index 20d397a29e..d1271017c6 100644 --- a/Code/Editor/EditorViewportSettings.h +++ b/Code/Editor/EditorViewportSettings.h @@ -71,8 +71,8 @@ namespace SandboxEditor SANDBOX_API float CameraDollyMotionSpeed(); SANDBOX_API void SetCameraDollyMotionSpeed(float speed); - SANDBOX_API bool CameraOrbitYawRotationInverted(); - SANDBOX_API void SetCameraOrbitYawRotationInverted(bool inverted); + SANDBOX_API bool CameraPivotYawRotationInverted(); + SANDBOX_API void SetCameraPivotYawRotationInverted(bool inverted); SANDBOX_API bool CameraPanInvertedX(); SANDBOX_API void SetCameraPanInvertedX(bool inverted); @@ -119,8 +119,8 @@ namespace SandboxEditor SANDBOX_API AzFramework::InputChannelId CameraTranslateBoostChannelId(); SANDBOX_API void SetCameraTranslateBoostChannelId(AZStd::string_view cameraTranslateBoostId); - SANDBOX_API AzFramework::InputChannelId CameraOrbitChannelId(); - SANDBOX_API void SetCameraOrbitChannelId(AZStd::string_view cameraOrbitId); + SANDBOX_API AzFramework::InputChannelId CameraPivotChannelId(); + SANDBOX_API void SetCameraPivotChannelId(AZStd::string_view cameraPivotId); SANDBOX_API AzFramework::InputChannelId CameraFreeLookChannelId(); SANDBOX_API void SetCameraFreeLookChannelId(AZStd::string_view cameraFreeLookId); @@ -128,12 +128,12 @@ namespace SandboxEditor SANDBOX_API AzFramework::InputChannelId CameraFreePanChannelId(); SANDBOX_API void SetCameraFreePanChannelId(AZStd::string_view cameraFreePanId); - SANDBOX_API AzFramework::InputChannelId CameraOrbitLookChannelId(); - SANDBOX_API void SetCameraOrbitLookChannelId(AZStd::string_view cameraOrbitLookId); + SANDBOX_API AzFramework::InputChannelId CameraPivotLookChannelId(); + SANDBOX_API void SetCameraPivotLookChannelId(AZStd::string_view cameraPivotLookId); - SANDBOX_API AzFramework::InputChannelId CameraOrbitDollyChannelId(); - SANDBOX_API void SetCameraOrbitDollyChannelId(AZStd::string_view cameraOrbitDollyId); + SANDBOX_API AzFramework::InputChannelId CameraPivotDollyChannelId(); + SANDBOX_API void SetCameraPivotDollyChannelId(AZStd::string_view cameraPivotDollyId); - SANDBOX_API AzFramework::InputChannelId CameraOrbitPanChannelId(); - SANDBOX_API void SetCameraOrbitPanChannelId(AZStd::string_view cameraOrbitPanId); + SANDBOX_API AzFramework::InputChannelId CameraPivotPanChannelId(); + SANDBOX_API void SetCameraPivotPanChannelId(AZStd::string_view cameraPivotPanId); } // namespace SandboxEditor diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index 18667ac153..a3eb4d8329 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -17,15 +17,6 @@ namespace AzFramework { - AZ_CVAR( - float, - ed_cameraSystemDefaultPlaneHeight, - 34.0f, - nullptr, - AZ::ConsoleFunctorFlags::Null, - "The default height of the ground plane to do intersection tests against when orbiting"); - AZ_CVAR(float, ed_cameraSystemMinOrbitDistance, 10.0f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); - AZ_CVAR(float, ed_cameraSystemMaxOrbitDistance, 50.0f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR( bool, ed_cameraSystemUseCursor, @@ -135,8 +126,8 @@ namespace AzFramework camera.m_pitch = eulerAngles.GetX(); camera.m_yaw = eulerAngles.GetZ(); - // note: m_lookDist is negative so we must invert it here - camera.m_lookAt = transform.GetTranslation() + (camera.Rotation().GetBasisY() * -camera.m_lookDist); + camera.m_pivot = transform.GetTranslation(); + camera.m_offset = AZ::Vector3::CreateZero(); } bool CameraSystem::HandleEvents(const InputEvent& event) @@ -320,14 +311,8 @@ namespace AzFramework nextCamera.m_pitch -= float(cursorDelta.m_y) * rotateSpeed * Invert(m_invertPitchFn()); nextCamera.m_yaw -= float(cursorDelta.m_x) * rotateSpeed * Invert(m_invertYawFn()); - const auto clampRotation = [](const float angle) - { - return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); - }; - - nextCamera.m_yaw = clampRotation(nextCamera.m_yaw); - // clamp pitch to be +/-90 degrees - nextCamera.m_pitch = AZ::GetClamp(nextCamera.m_pitch, -AZ::Constants::HalfPi, AZ::Constants::HalfPi); + nextCamera.m_yaw = WrapYawRotation(nextCamera.m_yaw); + nextCamera.m_pitch = ClampPitchRotation(nextCamera.m_pitch); return nextCamera; } @@ -337,9 +322,10 @@ namespace AzFramework m_rotateChannelId = rotateChannelId; } - PanCameraInput::PanCameraInput(const InputChannelId& panChannelId, PanAxesFn panAxesFn) + PanCameraInput::PanCameraInput(const InputChannelId& panChannelId, PanAxesFn panAxesFn, TranslationDeltaFn translationDeltaFn) : m_panAxesFn(AZStd::move(panAxesFn)) , m_panChannelId(panChannelId) + , m_translationDeltaFn(translationDeltaFn) { m_panSpeedFn = []() constexpr { @@ -375,11 +361,11 @@ namespace AzFramework const auto panAxes = m_panAxesFn(nextCamera); const float panSpeed = m_panSpeedFn(); - const auto deltaPanX = float(cursorDelta.m_x) * panAxes.m_horizontalAxis * panSpeed; - const auto deltaPanY = float(cursorDelta.m_y) * panAxes.m_verticalAxis * panSpeed; + const auto deltaPanX = aznumeric_cast(cursorDelta.m_x) * panAxes.m_horizontalAxis * panSpeed; + const auto deltaPanY = aznumeric_cast(cursorDelta.m_y) * panAxes.m_verticalAxis * panSpeed; - nextCamera.m_lookAt += deltaPanX * Invert(m_invertPanXFn()); - nextCamera.m_lookAt += deltaPanY * -Invert(m_invertPanYFn()); + m_translationDeltaFn(nextCamera, deltaPanX * Invert(m_invertPanXFn())); + m_translationDeltaFn(nextCamera, deltaPanY * -Invert(m_invertPanYFn())); return nextCamera; } @@ -426,8 +412,11 @@ namespace AzFramework } TranslateCameraInput::TranslateCameraInput( - TranslationAxesFn translationAxesFn, const TranslateCameraInputChannelIds& translateCameraInputChannelIds) + const TranslateCameraInputChannelIds& translateCameraInputChannelIds, + TranslationAxesFn translationAxesFn, + TranslationDeltaFn translateDeltaFn) : m_translationAxesFn(AZStd::move(translationAxesFn)) + , m_translateDeltaFn(AZStd::move(translateDeltaFn)) , m_translateCameraInputChannelIds(translateCameraInputChannelIds) { m_translateSpeedFn = []() constexpr @@ -497,32 +486,32 @@ namespace AzFramework if ((m_translation & TranslationType::Forward) == TranslationType::Forward) { - nextCamera.m_lookAt += axisY * speed * deltaTime; + m_translateDeltaFn(nextCamera, axisY * speed * deltaTime); } if ((m_translation & TranslationType::Backward) == TranslationType::Backward) { - nextCamera.m_lookAt -= axisY * speed * deltaTime; + m_translateDeltaFn(nextCamera, -axisY * speed * deltaTime); } if ((m_translation & TranslationType::Left) == TranslationType::Left) { - nextCamera.m_lookAt -= axisX * speed * deltaTime; + m_translateDeltaFn(nextCamera, -axisX * speed * deltaTime); } if ((m_translation & TranslationType::Right) == TranslationType::Right) { - nextCamera.m_lookAt += axisX * speed * deltaTime; + m_translateDeltaFn(nextCamera, axisX * speed * deltaTime); } if ((m_translation & TranslationType::Up) == TranslationType::Up) { - nextCamera.m_lookAt += axisZ * speed * deltaTime; + m_translateDeltaFn(nextCamera, axisZ * speed * deltaTime); } if ((m_translation & TranslationType::Down) == TranslationType::Down) { - nextCamera.m_lookAt -= axisZ * speed * deltaTime; + m_translateDeltaFn(nextCamera, -axisZ * speed * deltaTime); } if (Ending()) @@ -544,16 +533,20 @@ namespace AzFramework m_translateCameraInputChannelIds = translateCameraInputChannelIds; } - OrbitCameraInput::OrbitCameraInput(const InputChannelId& orbitChannelId) - : m_orbitChannelId(orbitChannelId) + PivotCameraInput::PivotCameraInput(const InputChannelId& pivotChannelId) + : m_pivotChannelId(pivotChannelId) { + m_pivotFn = []([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) + { + return AZ::Vector3::CreateZero(); + }; } - bool OrbitCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, const float scrollDelta) + bool PivotCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, const float scrollDelta) { if (const auto* input = AZStd::get_if(&event)) { - if (input->m_channelId == m_orbitChannelId) + if (input->m_channelId == m_pivotChannelId) { if (input->m_state == InputChannel::State::Began) { @@ -568,85 +561,46 @@ namespace AzFramework if (Active()) { - return m_orbitCameras.HandleEvents(event, cursorDelta, scrollDelta); + return m_pivotCameras.HandleEvents(event, cursorDelta, scrollDelta); } return !Idle(); } - Camera OrbitCameraInput::StepCamera( + Camera PivotCameraInput::StepCamera( const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime) { Camera nextCamera = targetCamera; if (Beginning()) { - const auto hasLookAt = [&nextCamera, &targetCamera, &lookAtFn = m_lookAtFn] - { - if (lookAtFn) - { - // pass through the camera's position and look vector for use in the lookAt function - if (const auto lookAt = lookAtFn(targetCamera.Translation(), targetCamera.Rotation().GetBasisY())) - { - // default to internal look at behavior if the look at point matches the camera translation - if (targetCamera.m_lookAt.IsClose(*lookAt)) - { - return false; - } - - auto transform = AZ::Transform::CreateLookAt(targetCamera.m_lookAt, *lookAt); - nextCamera.m_lookDist = -lookAt->GetDistance(targetCamera.m_lookAt); - UpdateCameraFromTransform(nextCamera, transform); - - return true; - } - } - return false; - }(); - - if (!hasLookAt) - { - float hit_distance = 0.0f; - AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateAxisZ(ed_cameraSystemDefaultPlaneHeight)) - .CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY(), hit_distance); - - if (hit_distance > 0.0f) - { - hit_distance = AZStd::min(hit_distance, ed_cameraSystemMaxOrbitDistance); - nextCamera.m_lookDist = -hit_distance; - nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * hit_distance; - } - else - { - nextCamera.m_lookDist = -ed_cameraSystemMinOrbitDistance; - nextCamera.m_lookAt = - targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * ed_cameraSystemMinOrbitDistance; - } - } + nextCamera.m_pivot = m_pivotFn(targetCamera.Translation(), targetCamera.Rotation().GetBasisY()); + nextCamera.m_offset = nextCamera.View().TransformPoint(targetCamera.Translation()); } if (Active()) { - nextCamera = m_orbitCameras.StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime); + MovePivotDetached(nextCamera, m_pivotFn(targetCamera.Translation(), targetCamera.Rotation().GetBasisY())); + nextCamera = m_pivotCameras.StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime); } if (Ending()) { - m_orbitCameras.Reset(); + m_pivotCameras.Reset(); - nextCamera.m_lookAt = nextCamera.Translation(); - nextCamera.m_lookDist = 0.0f; + nextCamera.m_pivot = nextCamera.Translation(); + nextCamera.m_offset = AZ::Vector3::CreateZero(); } return nextCamera; } - void OrbitCameraInput::SetOrbitInputChannelId(const InputChannelId& orbitChanneId) + void PivotCameraInput::SetPivotInputChannelId(const InputChannelId& pivotChanneId) { - m_orbitChannelId = orbitChanneId; + m_pivotChannelId = pivotChanneId; } - OrbitDollyScrollCameraInput::OrbitDollyScrollCameraInput() + PivotDollyScrollCameraInput::PivotDollyScrollCameraInput() { m_scrollSpeedFn = []() constexpr { @@ -654,7 +608,7 @@ namespace AzFramework }; } - bool OrbitDollyScrollCameraInput::HandleEvents( + bool PivotDollyScrollCameraInput::HandleEvents( const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta) { if (const auto* scroll = AZStd::get_if(&event)) @@ -665,46 +619,61 @@ namespace AzFramework return !Idle(); } - Camera OrbitDollyScrollCameraInput::StepCamera( + static Camera PivotDolly(const Camera& targetCamera, const float delta) + { + Camera nextCamera = targetCamera; + + const auto pivotDirection = targetCamera.m_offset.GetNormalized(); + nextCamera.m_offset -= pivotDirection * delta; + const auto pivotDot = targetCamera.m_offset.Dot(nextCamera.m_offset); + const auto distance = nextCamera.m_offset.GetLength() * AZ::GetSign(pivotDot); + + const auto minDistance = 0.01f; + if (distance < minDistance || pivotDot < 0.0f) + { + nextCamera.m_offset = pivotDirection * minDistance; + } + + return nextCamera; + } + + Camera PivotDollyScrollCameraInput::StepCamera( const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta, [[maybe_unused]] const float deltaTime) { - Camera nextCamera = targetCamera; - nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + scrollDelta * m_scrollSpeedFn(), 0.0f); + const auto nextCamera = PivotDolly(targetCamera, aznumeric_cast(scrollDelta) * m_scrollSpeedFn()); EndActivation(); return nextCamera; } - OrbitDollyCursorMoveCameraInput::OrbitDollyCursorMoveCameraInput(const InputChannelId& dollyChannelId) + PivotDollyMotionCameraInput::PivotDollyMotionCameraInput(const InputChannelId& dollyChannelId) : m_dollyChannelId(dollyChannelId) { - m_cursorSpeedFn = []() constexpr + m_motionSpeedFn = []() constexpr { return 0.01f; }; } - bool OrbitDollyCursorMoveCameraInput::HandleEvents( + bool PivotDollyMotionCameraInput::HandleEvents( const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta) { HandleActivationEvents(event, m_dollyChannelId, cursorDelta, m_clickDetector, *this); return CameraInputUpdatingAfterMotion(*this); } - Camera OrbitDollyCursorMoveCameraInput::StepCamera( + Camera PivotDollyMotionCameraInput::StepCamera( const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta, [[maybe_unused]] const float deltaTime) { - Camera nextCamera = targetCamera; - nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + float(cursorDelta.m_y) * m_cursorSpeedFn(), 0.0f); - return nextCamera; + return PivotDolly(targetCamera, aznumeric_cast(cursorDelta.m_y) * m_motionSpeedFn()); } - void OrbitDollyCursorMoveCameraInput::SetDollyInputChannelId(const InputChannelId& dollyChannelId) + void PivotDollyMotionCameraInput::SetDollyInputChannelId(const InputChannelId& dollyChannelId) { m_dollyChannelId = dollyChannelId; } @@ -739,7 +708,7 @@ namespace AzFramework const auto translation_basis = LookTranslation(nextCamera); const auto axisY = translation_basis.GetBasisY(); - nextCamera.m_lookAt += axisY * scrollDelta * m_scrollSpeedFn(); + nextCamera.m_pivot += axisY * scrollDelta * m_scrollSpeedFn(); EndActivation(); @@ -790,13 +759,13 @@ namespace AzFramework { const float moveRate = AZStd::exp2(cameraProps.m_translateSmoothnessFn()); const float moveTime = AZStd::exp2(-moveRate * deltaTime); - camera.m_lookDist = AZ::Lerp(targetCamera.m_lookDist, currentCamera.m_lookDist, moveTime); - camera.m_lookAt = targetCamera.m_lookAt.Lerp(currentCamera.m_lookAt, moveTime); + camera.m_pivot = targetCamera.m_pivot.Lerp(currentCamera.m_pivot, moveTime); + camera.m_offset = targetCamera.m_offset.Lerp(currentCamera.m_offset, moveTime); } else { - camera.m_lookDist = targetCamera.m_lookDist; - camera.m_lookAt = targetCamera.m_lookAt; + camera.m_pivot = targetCamera.m_pivot; + camera.m_offset = targetCamera.m_offset; } return camera; diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h index 69e8b66434..c44d951292 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h @@ -29,17 +29,15 @@ namespace AzFramework //! @note Order of rotation is Z, Y, X. AZ::Vector3 EulerAngles(const AZ::Matrix3x3& orientation); - //! A simple camera representation using spherical coordinates as input (pitch, yaw and look distance). + //! A simple camera representation using spherical coordinates as input (pitch, yaw, pivot and offset). //! The cameras transform and view can be obtained through accessor functions that use the internal //! spherical coordinates to calculate the position and orientation. struct Camera { - AZ::Vector3 m_lookAt = AZ::Vector3::CreateZero(); //!< Position of camera when m_lookDist is zero, - //!< or position of m_lookAt when m_lookDist is greater - //!< than zero. - float m_yaw{ 0.0 }; //!< Yaw rotation of camera (stored in radians) usually clamped to 0-360 degrees (0-2Pi radians). - float m_pitch{ 0.0 }; //!< Pitch rotation of the camera (stored in radians) usually clamped to +/-90 degrees (-Pi/2 - Pi/2 radians). - float m_lookDist{ 0.0 }; //!< Zero gives first person free look, otherwise orbit about m_lookAt + AZ::Vector3 m_pivot = AZ::Vector3::CreateZero(); //!< Pivot point to rotate about (modified in world space). + AZ::Vector3 m_offset = AZ::Vector3::CreateZero(); //!< Offset relative to pivot (modified in camera space). + float m_yaw = 0.0f; //!< Yaw rotation of camera (stored in radians) usually clamped to 0-360 degrees (0-2Pi radians). + float m_pitch = 0.0f; //!< Pitch rotation of the camera (stored in radians) usually clamped to +/-90 degrees (-Pi/2 - Pi/2 radians). //! View camera transform (V in model-view-projection matrix (MVP)). AZ::Transform View() const; @@ -51,6 +49,15 @@ namespace AzFramework AZ::Vector3 Translation() const; }; + //! Helper to allow the pivot to be positioned without altering the camera's position. + inline void MovePivotDetached(Camera& camera, const AZ::Vector3& pivot) + { + const auto& view = camera.View(); + const auto delta = view.TransformPoint(pivot) - view.TransformPoint(camera.m_pivot); + camera.m_offset -= delta; + camera.m_pivot = pivot; + } + inline AZ::Transform Camera::View() const { return Transform().GetInverse(); @@ -58,8 +65,8 @@ namespace AzFramework inline AZ::Transform Camera::Transform() const { - return AZ::Transform::CreateTranslation(m_lookAt) * AZ::Transform::CreateRotationZ(m_yaw) * - AZ::Transform::CreateRotationX(m_pitch) * AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(m_lookDist)); + return AZ::Transform::CreateTranslation(m_pivot) * AZ::Transform::CreateRotationZ(m_yaw) * AZ::Transform::CreateRotationX(m_pitch) * + AZ::Transform::CreateTranslation(m_offset); } inline AZ::Matrix3x3 Camera::Rotation() const @@ -279,21 +286,37 @@ namespace AzFramework public: bool HandleEvents(const InputEvent& event); Camera StepCamera(const Camera& targetCamera, float deltaTime); - bool HandlingEvents() const - { - return m_handlingEvents; - } + bool HandlingEvents() const; Cameras m_cameras; //!< Represents a collection of camera inputs that together provide a camera controller. private: - ScreenVector m_motionDelta; //!< The delta used for look/orbit/pan (rotation + translation) - two dimensional. + ScreenVector m_motionDelta; //!< The delta used for look/pivot/pan (rotation + translation) - two dimensional. CursorState m_cursorState; //!< The current and previous position of the cursor (used to calculate movement delta). float m_scrollDelta = 0.0f; //!< The delta used for dolly/movement (translation) - one dimensional. bool m_handlingEvents = false; //!< Is the camera system currently handling events (events are consumed and not propagated). }; - //! A camera input to handle motion deltas that can rotate or orbit the camera. + inline bool CameraSystem::HandlingEvents() const + { + return m_handlingEvents; + } + + //! Clamps pitch to be +/-90 degrees (-Pi/2, Pi/2). + //! @param pitch Pitch angle in radians. + inline float ClampPitchRotation(const float pitch) + { + return AZ::GetClamp(pitch, -AZ::Constants::HalfPi, AZ::Constants::HalfPi); + } + + //! Ensures yaw wraps between 0 and 360 degrees (0, 2Pi). + //! @param yaw Yaw angle in radians. + inline float WrapYawRotation(const float yaw) + { + return AZStd::fmod(yaw + AZ::Constants::TwoPi, AZ::Constants::TwoPi); + } + + //! A camera input to handle motion deltas that can rotate or pivot the camera. class RotateCameraInput : public CameraInput { public: @@ -332,8 +355,8 @@ namespace AzFramework return { orientation.GetBasisX(), orientation.GetBasisZ() }; } - //! PanAxes to use while in 'orbit' camera behavior. - inline PanAxes OrbitPan(const Camera& camera) + //! PanAxes to use while in 'pivot' camera behavior. + inline PanAxes PivotPan(const Camera& camera) { const AZ::Matrix3x3 orientation = camera.Rotation(); @@ -347,11 +370,23 @@ namespace AzFramework return { basisX, basisY }; } + using TranslationDeltaFn = AZStd::function; + + inline void TranslatePivot(Camera& camera, const AZ::Vector3& delta) + { + camera.m_pivot += delta; + } + + inline void TranslateOffset(Camera& camera, const AZ::Vector3& delta) + { + camera.m_offset += camera.View().TransformVector(delta); + } + //! A camera input to handle motion deltas that can pan the camera (translate in two axes). class PanCameraInput : public CameraInput { public: - PanCameraInput(const InputChannelId& panChannelId, PanAxesFn panAxesFn); + PanCameraInput(const InputChannelId& panChannelId, PanAxesFn panAxesFn, TranslationDeltaFn translationDeltaFn); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; @@ -365,6 +400,7 @@ namespace AzFramework private: PanAxesFn m_panAxesFn; //!< Builder for the particular pan axes (provided in the constructor). + TranslationDeltaFn m_translationDeltaFn; //!< How to apply the translation delta to the camera offset or pivot. InputChannelId m_panChannelId; //!< Input channel to begin the pan camera input. ClickDetector m_clickDetector; //!< Used to determine when a sufficient motion delta has occurred after an initial discrete input //!< event has started (press and move event). @@ -385,8 +421,8 @@ namespace AzFramework return AZ::Matrix3x3::CreateFromColumns(basisX, basisY, basisZ); } - //! TranslationAxes to use while in 'orbit' camera behavior. - inline AZ::Matrix3x3 OrbitTranslation(const Camera& camera) + //! TranslationAxes to use while in 'pivot' camera behavior. + inline AZ::Matrix3x3 PivotTranslation(const Camera& camera) { const AZ::Matrix3x3 orientation = camera.Rotation(); @@ -417,8 +453,10 @@ namespace AzFramework class TranslateCameraInput : public CameraInput { public: - explicit TranslateCameraInput( - TranslationAxesFn translationAxesFn, const TranslateCameraInputChannelIds& translateCameraInputChannelIds); + TranslateCameraInput( + const TranslateCameraInputChannelIds& translateCameraInputChannelIds, + TranslationAxesFn translationAxesFn, + TranslationDeltaFn translateDeltaFn); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; @@ -492,15 +530,16 @@ namespace AzFramework TranslationType m_translation = TranslationType::Nil; //!< Types of translation the camera input is under. TranslationAxesFn m_translationAxesFn; //!< Builder for translation axes. + TranslationDeltaFn m_translateDeltaFn; //!< How to apply the translation delta to the camera offset or pivot. TranslateCameraInputChannelIds m_translateCameraInputChannelIds; //!< Input channel ids that map to internal translation types. bool m_boost = false; //!< Is the translation speed currently being multiplied/scaled upwards. }; - //! A camera input to handle discrete scroll events that can modify the camera look distance. - class OrbitDollyScrollCameraInput : public CameraInput + //! A camera input to handle discrete scroll events that can modify the camera pivot distance. + class PivotDollyScrollCameraInput : public CameraInput { public: - OrbitDollyScrollCameraInput(); + PivotDollyScrollCameraInput(); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; @@ -509,11 +548,11 @@ namespace AzFramework AZStd::function m_scrollSpeedFn; }; - //! A camera input to handle motion deltas that can modify the camera look distance. - class OrbitDollyCursorMoveCameraInput : public CameraInput + //! A camera input to handle motion deltas that can modify the camera pivot distance. + class PivotDollyMotionCameraInput : public CameraInput { public: - explicit OrbitDollyCursorMoveCameraInput(const InputChannelId& dollyChannelId); + explicit PivotDollyMotionCameraInput(const InputChannelId& dollyChannelId); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; @@ -521,7 +560,7 @@ namespace AzFramework void SetDollyInputChannelId(const InputChannelId& dollyChannelId); - AZStd::function m_cursorSpeedFn; + AZStd::function m_motionSpeedFn; private: InputChannelId m_dollyChannelId; //!< Input channel to begin the dolly cursor camera input. @@ -544,36 +583,36 @@ namespace AzFramework //! A camera input that doubles as its own set of camera inputs. //! It is 'exclusive', so does not overlap with other sibling camera inputs - it runs its own set of camera inputs as 'children'. - class OrbitCameraInput : public CameraInput + class PivotCameraInput : public CameraInput { public: - using LookAtFn = AZStd::function(const AZ::Vector3& position, const AZ::Vector3& direction)>; + using PivotFn = AZStd::function; - explicit OrbitCameraInput(const InputChannelId& orbitChannelId); + explicit PivotCameraInput(const InputChannelId& pivotChannelId); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; bool Exclusive() const override; - void SetOrbitInputChannelId(const InputChannelId& orbitChanneId); + void SetPivotInputChannelId(const InputChannelId& pivotChanneId); - Cameras m_orbitCameras; //!< The camera inputs to run when this camera input is active (only these will run as it is exclusive). + Cameras m_pivotCameras; //!< The camera inputs to run when this camera input is active (only these will run as it is exclusive). - //! Override the default behavior for how a look-at point is calculated. - void SetLookAtFn(const LookAtFn& lookAtFn); + //! Override the default behavior for how a pivot point is calculated. + void SetPivotFn(PivotFn pivotFn); private: - InputChannelId m_orbitChannelId; //!< Input channel to begin the orbit camera input. - LookAtFn m_lookAtFn; //!< The look-at behavior to use for this orbit camera (how is the look-at point calculated/retrieved). + InputChannelId m_pivotChannelId; //!< Input channel to begin the pivot camera input. + PivotFn m_pivotFn; //!< The pivot position to use for this pivot camera (how is the pivot point calculated/retrieved). }; - inline void OrbitCameraInput::SetLookAtFn(const LookAtFn& lookAtFn) + inline void PivotCameraInput::SetPivotFn(PivotFn pivotFn) { - m_lookAtFn = lookAtFn; + m_pivotFn = AZStd::move(pivotFn); } - inline bool OrbitCameraInput::Exclusive() const + inline bool PivotCameraInput::Exclusive() const { return true; } diff --git a/Code/Framework/AzFramework/Tests/CameraInputTests.cpp b/Code/Framework/AzFramework/Tests/CameraInputTests.cpp index df7d22f7ca..1e0c805587 100644 --- a/Code/Framework/AzFramework/Tests/CameraInputTests.cpp +++ b/Code/Framework/AzFramework/Tests/CameraInputTests.cpp @@ -26,7 +26,8 @@ namespace UnitTest { constexpr float deltaTime = 0.01666f; // 60fps const bool consumed = m_cameraSystem->HandleEvents(event); - m_camera = m_cameraSystem->StepCamera(m_targetCamera, deltaTime); + m_targetCamera = m_cameraSystem->StepCamera(m_targetCamera, deltaTime); + m_camera = m_targetCamera; // no smoothing return consumed; } @@ -45,20 +46,38 @@ namespace UnitTest m_translateCameraInputChannelIds.m_boostChannelId = AzFramework::InputChannelId("keyboard_key_modifier_shift_l"); m_firstPersonRotateCamera = AZStd::make_shared(AzFramework::InputDeviceMouse::Button::Right); - m_firstPersonTranslateCamera = - AZStd::make_shared(AzFramework::LookTranslation, m_translateCameraInputChannelIds); + // set rotate speed to be a value that will scale motion delta (pixels moved) by a thousandth. + m_firstPersonRotateCamera->m_rotateSpeedFn = []() + { + return 0.001f; + }; - m_orbitCamera = AZStd::make_shared(m_orbitChannelId); - auto orbitRotateCamera = AZStd::make_shared(AzFramework::InputDeviceMouse::Button::Left); - auto orbitTranslateCamera = - AZStd::make_shared(AzFramework::OrbitTranslation, m_translateCameraInputChannelIds); + m_firstPersonTranslateCamera = AZStd::make_shared( + m_translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivot); - m_orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera); - m_orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera); + m_pivotCamera = AZStd::make_shared(m_pivotChannelId); + m_pivotCamera->SetPivotFn( + [this](const AZ::Vector3&, const AZ::Vector3&) + { + return m_pivot; + }); + + auto pivotRotateCamera = AZStd::make_shared(AzFramework::InputDeviceMouse::Button::Left); + // set rotate speed to be a value that will scale motion delta (pixels moved) by a thousandth. + pivotRotateCamera->m_rotateSpeedFn = []() + { + return 0.001f; + }; + + auto pivotTranslateCamera = AZStd::make_shared( + m_translateCameraInputChannelIds, AzFramework::PivotTranslation, AzFramework::TranslateOffset); + + m_pivotCamera->m_pivotCameras.AddCamera(pivotRotateCamera); + m_pivotCamera->m_pivotCameras.AddCamera(pivotTranslateCamera); m_cameraSystem->m_cameras.AddCamera(m_firstPersonRotateCamera); m_cameraSystem->m_cameras.AddCamera(m_firstPersonTranslateCamera); - m_cameraSystem->m_cameras.AddCamera(m_orbitCamera); + m_cameraSystem->m_cameras.AddCamera(m_pivotCamera); // these tests rely on using motion delta, not cursor positions (default is true) AzFramework::ed_cameraSystemUseCursor = false; @@ -68,7 +87,7 @@ namespace UnitTest { AzFramework::ed_cameraSystemUseCursor = true; - m_orbitCamera.reset(); + m_pivotCamera.reset(); m_firstPersonRotateCamera.reset(); m_firstPersonTranslateCamera.reset(); @@ -78,24 +97,29 @@ namespace UnitTest AllocatorsTestFixture::TearDown(); } - AzFramework::InputChannelId m_orbitChannelId = AzFramework::InputChannelId("keyboard_key_modifier_alt_l"); + AzFramework::InputChannelId m_pivotChannelId = AzFramework::InputChannelId("keyboard_key_modifier_alt_l"); AzFramework::TranslateCameraInputChannelIds m_translateCameraInputChannelIds; AZStd::shared_ptr m_firstPersonRotateCamera; AZStd::shared_ptr m_firstPersonTranslateCamera; - AZStd::shared_ptr m_orbitCamera; + AZStd::shared_ptr m_pivotCamera; + AZ::Vector3 m_pivot = AZ::Vector3::CreateZero(); + + //! This is approximately Pi/2 * 1000 - this can be used to rotate the camera 90 degrees (pitch or yaw based + //! on vertical or horizontal motion) as the rotate speed function is set to be 1/1000. + inline static const int PixelMotionDelta = 1570; }; - TEST_F(CameraInputFixture, BeginAndEndOrbitCameraInputConsumesCorrectEvents) + TEST_F(CameraInputFixture, BeginAndEndPivotCameraInputConsumesCorrectEvents) { - // begin orbit camera + // begin pivot camera const bool consumed1 = HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceKeyboard::Key::ModifierAltL, AzFramework::InputChannel::State::Began }); - // begin listening for orbit rotate (click detector) - event is not consumed + // begin listening for pivot rotate (click detector) - event is not consumed const bool consumed2 = HandleEventAndUpdate( AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began }); - // begin orbit rotate (mouse has moved sufficient distance to initiate) + // begin pivot rotate (mouse has moved sufficient distance to initiate) const bool consumed3 = HandleEventAndUpdate(AzFramework::HorizontalMotionEvent{ 5 }); - // end orbit (mouse up) - event is not consumed + // end pivot (mouse up) - event is not consumed const bool consumed4 = HandleEventAndUpdate( AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Ended }); @@ -236,29 +260,110 @@ namespace UnitTest EXPECT_TRUE(activationEnded); } - TEST_F(CameraInputFixture, OrbitCameraInputHandlesLookAtPointAndSelfAtSamePositionWhenOrbiting) + TEST_F(CameraInputFixture, PivotCameraInputHandlesLookAtPointAndSelfAtSamePositionWhenPivoting) { // create pathological lookAtFn that just returns the same position as the camera - m_orbitCamera->SetLookAtFn( + m_pivotCamera->SetPivotFn( [](const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) { return position; }); + const auto expectedCameraPosition = AZ::Vector3(10.0f, 10.0f, 10.0f); AzFramework::UpdateCameraFromTransform( m_targetCamera, AZ::Transform::CreateFromQuaternionAndTranslation( - AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 10.0f, 10.0f))); + AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), expectedCameraPosition)); - m_camera = m_targetCamera; + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_pivotChannelId, AzFramework::InputChannel::State::Began }); - HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began }); + // verify the camera yaw has not changed and pivot point matches the expected camera position + using ::testing::FloatNear; + EXPECT_THAT(m_camera.m_yaw, FloatNear(AZ::DegToRad(90.0f), 0.001f)); + EXPECT_THAT(m_camera.m_pitch, FloatNear(0.0f, 0.001f)); + EXPECT_THAT(m_camera.m_offset, IsClose(AZ::Vector3::CreateZero())); + EXPECT_THAT(m_camera.m_pivot, IsClose(expectedCameraPosition)); + } - // verify the camera yaw has not changed and the look at point - // does not match that of the camera translation - using ::testing::Eq; - using ::testing::Not; - EXPECT_THAT(m_camera.m_yaw, Eq(AZ::DegToRad(90.0f))); - EXPECT_THAT(m_camera.m_lookAt, Not(IsClose(m_camera.Translation()))); + TEST_F(CameraInputFixture, FirstPersonRotateCameraInputRotatesYawByNinetyDegreesWithRequiredPixelDelta) + { + const auto cameraStartingPosition = AZ::Vector3::CreateAxisY(-10.0f); + m_targetCamera.m_pivot = cameraStartingPosition; + + HandleEventAndUpdate( + AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Right, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::HorizontalMotionEvent{ PixelMotionDelta }); + + const float expectedYaw = AzFramework::WrapYawRotation(-AZ::Constants::HalfPi); + + using ::testing::FloatNear; + EXPECT_THAT(m_camera.m_yaw, FloatNear(expectedYaw, 0.001f)); + EXPECT_THAT(m_camera.m_pitch, FloatNear(0.0f, 0.001f)); + EXPECT_THAT(m_camera.m_pivot, IsClose(cameraStartingPosition)); + EXPECT_THAT(m_camera.m_offset, IsClose(AZ::Vector3::CreateZero())); + } + + TEST_F(CameraInputFixture, FirstPersonRotateCameraInputRotatesPitchByNinetyDegreesWithRequiredPixelDelta) + { + const auto cameraStartingPosition = AZ::Vector3::CreateAxisY(-10.0f); + m_targetCamera.m_pivot = cameraStartingPosition; + + HandleEventAndUpdate( + AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Right, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::VerticalMotionEvent{ PixelMotionDelta }); + + const float expectedPitch = AzFramework::ClampPitchRotation(-AZ::Constants::HalfPi); + + using ::testing::FloatNear; + EXPECT_THAT(m_camera.m_yaw, FloatNear(0.0f, 0.001f)); + EXPECT_THAT(m_camera.m_pitch, FloatNear(expectedPitch, 0.001f)); + EXPECT_THAT(m_camera.m_pivot, IsClose(cameraStartingPosition)); + EXPECT_THAT(m_camera.m_offset, IsClose(AZ::Vector3::CreateZero())); + } + + TEST_F(CameraInputFixture, PivotRotateCameraInputRotatesPitchOffsetByNinetyDegreesWithRequiredPixelDelta) + { + const auto cameraStartingPosition = AZ::Vector3::CreateAxisY(-20.0f); + m_targetCamera.m_pivot = cameraStartingPosition; + + m_pivot = AZ::Vector3::CreateAxisY(-10.0f); + + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_pivotChannelId, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate( + AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::VerticalMotionEvent{ PixelMotionDelta }); + + const auto expectedCameraEndingPosition = AZ::Vector3(0.0f, -10.0f, 10.0f); + const float expectedPitch = AzFramework::ClampPitchRotation(-AZ::Constants::HalfPi); + + using ::testing::FloatNear; + EXPECT_THAT(m_camera.m_yaw, FloatNear(0.0f, 0.001f)); + EXPECT_THAT(m_camera.m_pitch, FloatNear(expectedPitch, 0.001f)); + EXPECT_THAT(m_camera.m_pivot, IsClose(m_pivot)); + EXPECT_THAT(m_camera.m_offset, IsClose(AZ::Vector3::CreateAxisY(-10.0f))); + EXPECT_THAT(m_camera.Translation(), IsCloseTolerance(expectedCameraEndingPosition, 0.01f)); + } + + TEST_F(CameraInputFixture, PivotRotateCameraInputRotatesYawOffsetByNinetyDegreesWithRequiredPixelDelta) + { + const auto cameraStartingPosition = AZ::Vector3(15.0f, -20.0f, 0.0f); + m_targetCamera.m_pivot = cameraStartingPosition; + + m_pivot = AZ::Vector3(10.0f, -10.0f, 0.0f); + + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_pivotChannelId, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate( + AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::HorizontalMotionEvent{ -PixelMotionDelta }); + + const auto expectedCameraEndingPosition = AZ::Vector3(20.0f, -5.0f, 0.0f); + const float expectedYaw = AzFramework::WrapYawRotation(AZ::Constants::HalfPi); + + using ::testing::FloatNear; + EXPECT_THAT(m_camera.m_yaw, FloatNear(expectedYaw, 0.001f)); + EXPECT_THAT(m_camera.m_pitch, FloatNear(0.0f, 0.001f)); + EXPECT_THAT(m_camera.m_pivot, IsClose(m_pivot)); + EXPECT_THAT(m_camera.m_offset, IsClose(AZ::Vector3(5.0f, -10.0f, 0.0f))); + EXPECT_THAT(m_camera.Translation(), IsCloseTolerance(expectedCameraEndingPosition, 0.01f)); } } // namespace UnitTest diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h index 4956fbc1dc..32897ab4d9 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -103,7 +102,6 @@ namespace AtomToolsFramework class ModularViewportCameraControllerInstance final : public AzFramework::MultiViewportControllerInstanceInterface , public ModularViewportCameraControllerRequestBus::Handler - , private AzFramework::ViewportDebugDisplayEventBus::Handler { public: explicit ModularViewportCameraControllerInstance(AzFramework::ViewportId viewportId, ModularViewportCameraController* controller); @@ -121,9 +119,6 @@ namespace AtomToolsFramework void ClearReferenceFrame() override; private: - // AzFramework::ViewportDebugDisplayEventBus overrides ... - void DisplayViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; - //! Update the reference frame after a change has been made to the camera //! view without updating the internal camera via user input. void RefreshReferenceFrame(); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp index bcc9a08f77..0bdd6fb55c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -21,15 +21,6 @@ namespace AtomToolsFramework { - AZ_CVAR( - AZ::Color, - ed_cameraSystemOrbitPointColor, - AZ::Color::CreateFromRgba(255, 255, 255, 255), - nullptr, - AZ::ConsoleFunctorFlags::Null, - ""); - AZ_CVAR(float, ed_cameraSystemOrbitPointSize, 0.1f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); - AZ::Transform TransformFromMatrix4x4(const AZ::Matrix4x4& matrix) { const auto rotation = AZ::Matrix3x3::CreateFromMatrix4x4(matrix); @@ -200,14 +191,12 @@ namespace AtomToolsFramework m_cameraViewMatrixChangeHandler = AZ::RPI::ViewportContext::MatrixChangedEvent::Handler(handleCameraChange); m_modularCameraViewportContext->ConnectViewMatrixChangedHandler(m_cameraViewMatrixChangeHandler); - AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); ModularViewportCameraControllerRequestBus::Handler::BusConnect(viewportId); } ModularViewportCameraControllerInstance::~ModularViewportCameraControllerInstance() { ModularViewportCameraControllerRequestBus::Handler::BusDisconnect(); - AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect(); } bool ModularViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) @@ -272,7 +261,8 @@ namespace AtomToolsFramework const AZ::Vector3 eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(current)); m_camera.m_pitch = eulerAngles.GetX(); m_camera.m_yaw = eulerAngles.GetZ(); - m_camera.m_lookAt = current.GetTranslation(); + m_camera.m_pivot = current.GetTranslation(); + m_camera.m_offset = AZ::Vector3::CreateZero(); m_targetCamera = m_camera; m_modularCameraViewportContext->SetCameraTransform(current); @@ -287,17 +277,6 @@ namespace AtomToolsFramework m_updatingTransformInternally = false; } - void ModularViewportCameraControllerInstance::DisplayViewport( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) - { - if (const float alpha = AZStd::min(-m_camera.m_lookDist / 5.0f, 1.0f); alpha > AZ::Constants::FloatEpsilon) - { - const AZ::Color orbitPointColor = ed_cameraSystemOrbitPointColor; - debugDisplay.SetColor(orbitPointColor.GetR(), orbitPointColor.GetG(), orbitPointColor.GetB(), alpha); - debugDisplay.DrawWireSphere(m_camera.m_lookAt, ed_cameraSystemOrbitPointSize); - } - } - void ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance) { m_cameraMode = CameraMode::Animation; @@ -325,8 +304,8 @@ namespace AtomToolsFramework m_referenceFrameOverride = worldFromLocal; m_targetCamera.m_pitch = 0.0f; m_targetCamera.m_yaw = 0.0f; - m_targetCamera.m_lookAt = AZ::Vector3::CreateZero(); - m_targetCamera.m_lookDist = 0.0f; + m_targetCamera.m_offset = AZ::Vector3::CreateZero(); + m_targetCamera.m_pivot = AZ::Vector3::CreateZero(); m_camera = m_targetCamera; } From 6b75c3b9d71fcd454757ba119e94832a02c8f4fe Mon Sep 17 00:00:00 2001 From: nggieber Date: Wed, 29 Sep 2021 08:55:04 -0700 Subject: [PATCH 067/115] Fixed non-unity compile error Signed-off-by: nggieber --- Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h index 38b9bf68eb..4ca469098e 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h @@ -9,7 +9,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include #endif namespace O3DE::ProjectManager From bdc5cb1fff53955836044c0ac333e34b4232cab1 Mon Sep 17 00:00:00 2001 From: Artur K <96597+nemerle@users.noreply.github.com> Date: Wed, 29 Sep 2021 18:30:38 +0200 Subject: [PATCH 068/115] Replace PROFILE define with AZ_PROFILE_BUILD It now follows the schema defined by `AZ_DEBUG_BUILD` define instead. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- .../Execution/Interpreted/ExecutionInterpretedAPI.cpp | 2 +- cmake/Platform/Common/Configurations_common.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp index 8d324e95c0..4d7c8a2cda 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp @@ -503,7 +503,7 @@ namespace ScriptCanvas void InitializeInterpretedStatics(const RuntimeData& runtimeData) { -#if defined(PROFILE) || defined(AZ_DEBUG_BUILD) +#if defined(AZ_PROFILE_BUILD) || defined(AZ_DEBUG_BUILD) Execution::InitializeFromLuaStackFunctions(const_cast(runtimeData.m_debugMap)); #endif if (runtimeData.RequiresStaticInitialization()) diff --git a/cmake/Platform/Common/Configurations_common.cmake b/cmake/Platform/Common/Configurations_common.cmake index 15f7344958..d16dfa3eea 100644 --- a/cmake/Platform/Common/Configurations_common.cmake +++ b/cmake/Platform/Common/Configurations_common.cmake @@ -36,7 +36,7 @@ ly_append_configurations_options( AZ_BUILD_CONFIGURATION_TYPE="${LY_BUILD_CONFIGURATION_TYPE_DEBUG}" DEFINES_PROFILE _PROFILE - PROFILE + AZ_PROFILE_BUILD=1 NDEBUG AZ_ENABLE_TRACING AZ_ENABLE_DEBUG_TOOLS From f44169f7fad4a9a82aded47aeb5f47c3731fd5a6 Mon Sep 17 00:00:00 2001 From: Artur K <96597+nemerle@users.noreply.github.com> Date: Wed, 29 Sep 2021 18:31:01 +0200 Subject: [PATCH 069/115] Cleanup SerializeContext.h pt.1 (#4264) * Remove AssetSerializer inclusion from SerializeContext header Moved a few Reflect methods to new cpp files. In addition, some preparations for further header dependency reductions. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Fix smoke test lua failures. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Windows build fixes. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Missing license headers Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Fix white-space issues. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Code review fix for AzToolsFramework/AssetEditor/AssetEditorBus.h Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Fix inheritance list wrapping broken by older clang-format Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AssetEditor/AssetEditorRequestsHandler.h | 1 - Code/Editor/AssetEditor/AssetEditorWindow.h | 1 - .../ReflectedPropertyCtrl.cpp | 3 + .../ReflectedPropertyCtrl.h | 1 - .../ReflectedPropertyControl/ReflectedVar.h | 2 +- .../EditorPreferencesTreeWidgetItem.cpp | 3 + Code/Editor/MainWindow.cpp | 5 +- Code/Editor/PythonEditorFuncs.cpp | 1 + .../Editor/TrackView/TrackViewPythonFuncs.cpp | 1 + Code/Editor/ViewportTitleDlg.cpp | 3 +- .../AzCore/Asset/AssetManagerComponent.cpp | 1 + .../AzCore/AzCore/Asset/AssetSerializer.cpp | 1 + .../AzCore/AzCore/Component/EntityUtils.h | 6 +- .../AzCore/AzCore/Name/NameSerializer.cpp | 1 + .../AzCore/AzCore/Script/ScriptProperty.cpp | 2 + .../AzCore/AzCore/Script/ScriptProperty.h | 4 +- .../AzCore/AzCore/Serialization/DataPatch.cpp | 1 + .../Serialization/Json/JsonDeserializer.cpp | 1 + .../Serialization/Json/JsonSerializer.cpp | 2 + .../Serialization/Json/MapSerializer.cpp | 1 + .../AzCore/Serialization/ObjectStream.cpp | 1 + .../AzCore/Serialization/ObjectStream.h | 3 +- .../AzCore/Serialization/SerializeContext.cpp | 2 + .../AzCore/Serialization/SerializeContext.h | 19 +- .../AzCore/AzCore/Slice/SliceComponent.cpp | 1 + .../AzCore/Statistics/StatisticalProfiler.h | 3 +- .../Tests/AZStd/VariantSerialization.cpp | 1 + .../Tests/Asset/AssetManagerLoadingTests.cpp | 1 + .../Asset/AssetManagerStreamingTests.cpp | 1 + .../Tests/Asset/BaseAssetManagerTest.cpp | 1 + .../AzCore/Tests/AssetJsonSerializerTests.cpp | 1 + Code/Framework/AzCore/Tests/AssetManager.cpp | 1 + Code/Framework/AzCore/Tests/Serialization.cpp | 1 + .../AzFramework/Asset/AssetBundleManifest.h | 5 +- .../AzFramework/Asset/AssetSeedList.cpp | 1 + .../AzFramework/Asset/AssetSeedList.h | 1 - .../Asset/Benchmark/BenchmarkAsset.cpp | 1 + .../AzFramework/Asset/SimpleAsset.cpp | 33 +++ .../AzFramework/Asset/SimpleAsset.h | 34 +-- .../AzFramework/Asset/XmlSchemaAsset.h | 1 + .../Entity/EntityOwnershipServiceBus.h | 5 + .../AzFramework/Physics/ClassConverters.cpp | 1 + .../Physics/Collision/CollisionEvents.cpp | 1 + .../Physics/Collision/CollisionGroups.cpp | 2 + .../Physics/Common/PhysicsSceneQueries.cpp | 1 + .../Configuration/SystemConfiguration.cpp | 1 + .../AzFramework/Physics/Material.cpp | 2 + .../AzFramework/Physics/PhysicsScene.cpp | 1 + .../AzFramework/Physics/PhysicsSystem.cpp | 2 + .../AzFramework/AzFramework/Physics/Shape.h | 1 - .../Physics/ShapeConfiguration.cpp | 2 + .../AzFramework/Physics/ShapeConfiguration.h | 1 + .../AzFramework/AzFramework/Physics/Utils.cpp | 4 +- .../AzFramework/Script/ScriptComponent.cpp | 1 + .../Spawnable/SpawnableSystemComponent.cpp | 1 + .../StreamingInstall/StreamingInstall.cpp | 1 + .../StreamingInstallRequests.h | 2 - .../Serialization/ISerializer.inl | 2 +- .../Gallery/ReflectedPropertyEditorPage.cpp | 1 + .../AzToolsFramework/API/EditorEntityAPI.h | 1 + .../Application/ToolsApplication.cpp | 1 + .../Asset/AssetSystemComponent.cpp | 2 + .../AssetBundle/AssetBundleComponent.cpp | 1 + .../AssetEditor/AssetEditorBus.cpp | 24 ++ .../AssetEditor/AssetEditorBus.h | 18 +- .../AssetEditor/AssetEditorWidget.cpp | 1 + .../Entity/EditorEntityHelpers.cpp | 1 + .../Prefab/EditorPrefabComponent.cpp | 1 + .../Prefab/EditorPrefabComponent.h | 1 - .../Prefab/PrefabPublicRequestHandler.cpp | 2 + .../Spawnable/PrefabConversionPipeline.cpp | 1 + .../PropertyTreeEditor/PropertyTreeEditor.h | 1 + .../ToolsComponents/EditorLayerComponent.cpp | 1 + .../ToolsComponents/ScriptEditorComponent.cpp | 1 + .../UI/PropertyEditor/PropertyAssetCtrl.cpp | 1 + .../UI/PropertyEditor/PropertyAssetCtrl.hxx | 1 + .../aztoolsframework_files.cmake | 1 + .../Tests/PropertyTreeEditorTests.cpp | 1 + .../Maestro/Bus/SequenceComponentBus.h | 1 + .../AssetBuilderSDK/AssetBuilderSDK.cpp | 1 + .../SerializationDependencies.cpp | 1 + .../native/AssetManager/AssetCatalog.cpp | 1 + .../AssetManager/AssetRequestHandler.cpp | 3 +- .../SettingsRegistryBuilder.cpp | 1 + .../SerializationDependenciesTests.cpp | 1 + .../Importers/AssImpBlendShapeImporter.cpp | 1 + .../SceneCore/Containers/GraphObjectProxy.h | 4 + .../SceneCore/Containers/SceneManifest.cpp | 1 + Code/Tools/SceneAPI/SceneCore/DllMain.cpp | 1 + .../Behaviors/ScriptProcessorRuleBehavior.cpp | 1 + .../SceneData/GraphData/BlendShapeData.cpp | 1 + .../SceneData/GraphData/MaterialData.cpp | 1 + .../Code/Source/AWSCoreSystemComponent.cpp | 1 + .../Code/Tests/AWSCoreSystemComponentTest.cpp | 1 + .../AWSCoreEditorSystemComponentTest.cpp | 1 + ...AWSGameLiftCreateSessionOnQueueRequest.cpp | 5 +- .../AWSGameLiftCreateSessionRequest.cpp | 5 +- .../Request/AWSGameLiftJoinSessionRequest.cpp | 4 +- .../AWSGameLiftSearchSessionsRequest.cpp | 7 +- .../Source/ArcBallControllerComponent.cpp | 1 + .../SkinnedMesh/SkinnedMeshVertexStreams.h | 1 - .../DisplayMapperConfigurationDescriptor.cpp | 1 + .../Source/Material/MaterialAssignment.cpp | 2 + .../Code/Source/Utils/LightingPreset.cpp | 1 + .../Common/Code/Source/Utils/ModelPreset.cpp | 3 + .../Code/Include/Atom/RHI.Reflect/Handle.h | 1 + .../Source/RHI.Reflect/ShaderSemantic.cpp | 2 + .../Include/Atom/RPI.Public/Model/Model.h | 2 + .../Shader/ShaderVariantListSourceData.cpp | 3 +- .../Code/Source/RPI.Public/Model/Model.cpp | 1 + .../Source/RPI.Public/Model/ModelLodUtils.cpp | 2 + .../Source/RPI.Public/Model/ModelSystem.cpp | 2 + .../Source/RPI.Reflect/Buffer/BufferAsset.cpp | 1 + .../RPI.Reflect/Buffer/BufferAssetView.cpp | 1 + .../RPI.Reflect/Image/StreamingImageAsset.cpp | 1 + .../Image/StreamingImagePoolAsset.cpp | 1 + .../Material/LuaMaterialFunctor.cpp | 1 + .../RPI.Reflect/Material/MaterialAsset.cpp | 1 + .../Material/MaterialPropertyValue.cpp | 1 + .../RPI.Reflect/Material/ShaderCollection.cpp | 1 + .../Source/RPI.Reflect/Model/ModelAsset.cpp | 1 + .../RPI.Reflect/Model/ModelMaterialSlot.cpp | 1 + .../Model/MorphTargetMetaAsset.cpp | 1 + .../Source/RPI.Reflect/Shader/ShaderAsset.cpp | 1 + .../Document/AtomToolsDocumentRequestBus.h | 1 + .../InspectorPropertyGroupWidget.cpp | 1 + .../MaterialEditorViewportInputController.cpp | 1 + .../ViewportSettingsInspector.cpp | 1 + .../Utils/Code/Include/Atom/Utils/Utils.h | 1 + .../Source/Animation/AttachmentComponent.cpp | 1 + .../Animation/EditorAttachmentComponent.cpp | 1 + .../Decals/DecalComponentController.cpp | 1 + .../DiffuseProbeGridComponentController.cpp | 1 + .../EditorDiffuseProbeGridComponent.cpp | 1 + .../ImageBasedLightComponentConfig.cpp | 1 + .../Material/EditorMaterialComponentSlot.cpp | 1 + .../Material/MaterialComponentController.cpp | 9 +- .../Source/Mesh/MeshComponentController.cpp | 1 + .../DisplayMapperComponentConfig.cpp | 1 + .../EditorDisplayMapperComponent.cpp | 3 +- .../GradientWeightModifierComponent.cpp | 2 + .../LookModificationComponentConfig.cpp | 1 + .../LookModificationComponentController.cpp | 1 + .../RadiusWeightModifierComponent.cpp | 2 + .../ShapeWeightModifierComponent.cpp | 2 + ...ShapeWeightModifierComponentController.cpp | 1 + .../EditorReflectionProbeComponent.cpp | 2 + .../ReflectionProbeComponentController.cpp | 1 + .../SkyBox/HDRiSkyboxComponentConfig.cpp | 1 + .../Components/BlastFamilyComponent.cpp | 5 +- .../Components/BlastMeshDataComponent.cpp | 1 + .../Components/BlastSystemComponent.cpp | 1 + .../Editor/EditorBlastFamilyComponent.cpp | 1 + .../Editor/EditorBlastMeshDataComponent.cpp | 1 + .../AnimGraphFollowerParameterAction.cpp | 1 + .../Source/AnimGraphReferenceNode.cpp | 1 + ...imGraphSymbolicFollowerParameterAction.cpp | 1 + .../Integration/Components/ActorComponent.cpp | 1 + .../Components/AnimGraphComponent.cpp | 1 + .../Components/SimpleMotionComponent.cpp | 1 + .../Components/EditorActorComponent.cpp | 1 + .../Components/EditorAnimGraphComponent.cpp | 1 + .../Code/Tests/EMotionFXBuilderTests.cpp | 1 + .../Code/Tests/PythonAssetTypesTests.cpp | 1 + .../Tests/PythonReflectionComponentTests.cpp | 1 + .../Components/ImageGradientComponent.cpp | 1 + .../Source/Translation/TranslationAsset.cpp | 2 + .../LYCommonMenu/ImGuiLYEntityOutliner.cpp | 1 + .../Builders/LuaBuilder/LuaBuilderWorker.h | 16 +- .../Scripting/EditorSpawnerComponent.cpp | 1 + .../Source/Scripting/SpawnerComponent.cpp | 1 + .../Code/Tests/Builders/SliceBuilderTests.cpp | 1 + .../Code/Source/UiSpawnerComponent.cpp | 1 + .../Source/Components/NetBindComponent.cpp | 1 + .../Source/MultiplayerSystemComponent.cpp | 1 + .../NetworkSpawnableHolderComponent.cpp | 1 + .../Code/Source/Components/ClothComponent.cpp | 1 + .../ClothComponentMesh/ClothComponentMesh.cpp | 3 + .../Components/EditorClothComponent.cpp | 1 + .../Code/Source/Editor/MeshNodeHandler.cpp | 1 + .../Code/Source/Editor/MeshNodeHandler.h | 1 + .../Code/Source/Utils/MeshAssetHelper.cpp | 1 + .../Code/Editor/EditorClassConverters.cpp | 1 + .../Code/Source/EditorColliderComponent.cpp | 2 + .../Components/CharacterGameplayComponent.cpp | 1 + .../PrefabBuilder/PrefabBuilderTests.cpp | 1 + .../Source/PythonBuilderNotificationHandler.h | 1 + .../Code/Source/PythonBuilderWorker.cpp | 3 +- .../SceneProcessingConfigSystemComponent.cpp | 1 + .../Code/Builder/ScriptCanvasBuilder.cpp | 1 + Gems/ScriptCanvas/Code/Editor/Settings.h | 1 + .../View/Widgets/AssetGraphSceneDataBus.h | 1 + .../ScriptCanvas/Asset/RuntimeAsset.cpp | 1 + .../AutoGen/ScriptCanvasGrammar_Source.jinja | 1 + .../AutoGen/ScriptCanvasNodeable_Source.jinja | 1 + .../Libraries/Core/FunctionDefinitionNode.cpp | 1 + .../ScriptCanvas/Utils/VersionConverters.cpp | 1 + .../Code/Tests/ScriptCanvasBuilderTests.cpp | 1 + .../Nodes/BehaviorContextObjectTestNode.h | 3 + .../ScriptEventBroadcast.h | 5 +- .../ScriptEventMethod.h | 7 +- .../Include/ScriptEvents/ScriptEventMethod.h | 216 +++++------------- .../ScriptEvents/ScriptEventParameter.h | 107 +-------- .../Include/ScriptEvents/ScriptEventTypes.h | 8 + .../ScriptEvents/ScriptEventsAssetRef.h | 125 +--------- .../Source/Editor/ScriptEventsEditorGem.cpp | 1 + .../Code/Source/ScriptEventMethod.cpp | 167 ++++++++++++++ .../Code/Source/ScriptEventParameter.cpp | 122 ++++++++++ .../Code/Source/ScriptEventsAssetRef.cpp | 135 +++++++++++ .../Code/scriptevents_common_files.cmake | 3 + .../Source/InputConfigurationComponent.cpp | 7 +- .../Components/DescriptorListComponent.cpp | 1 + .../Components/MeshBlockerComponent.cpp | 1 + .../Source/DynamicSliceInstanceSpawner.cpp | 1 + .../Code/Source/PrefabInstanceSpawner.cpp | 1 + Gems/Vegetation/Code/Tests/VegetationMocks.h | 1 + .../Source/Asset/EditorWhiteBoxMeshAsset.cpp | 1 + .../Code/Source/EditorWhiteBoxComponent.cpp | 1 + 218 files changed, 861 insertions(+), 488 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.cpp create mode 100644 Gems/ScriptEvents/Code/Source/ScriptEventMethod.cpp create mode 100644 Gems/ScriptEvents/Code/Source/ScriptEventParameter.cpp create mode 100644 Gems/ScriptEvents/Code/Source/ScriptEventsAssetRef.cpp diff --git a/Code/Editor/AssetEditor/AssetEditorRequestsHandler.h b/Code/Editor/AssetEditor/AssetEditorRequestsHandler.h index ebfa84249d..bbe55e216a 100644 --- a/Code/Editor/AssetEditor/AssetEditorRequestsHandler.h +++ b/Code/Editor/AssetEditor/AssetEditorRequestsHandler.h @@ -7,7 +7,6 @@ */ #pragma once -#include #include #include diff --git a/Code/Editor/AssetEditor/AssetEditorWindow.h b/Code/Editor/AssetEditor/AssetEditorWindow.h index 2cf73ac282..63347d6ff3 100644 --- a/Code/Editor/AssetEditor/AssetEditorWindow.h +++ b/Code/Editor/AssetEditor/AssetEditorWindow.h @@ -9,7 +9,6 @@ #if !defined(Q_MOC_RUN) #include -#include #include #include #include diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp index 40ea71f577..1151137bfc 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp @@ -26,6 +26,9 @@ #include #include +//AzCore +#include + // Editor #include "Clipboard.h" diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h index 64a4341096..ed5d1915ac 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h @@ -12,7 +12,6 @@ #if !defined(Q_MOC_RUN) #include -#include #include #include "Include/EditorCoreAPI.h" #include "ReflectedPropertyItem.h" diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h index a15f8326d1..7c38465c5e 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h @@ -10,10 +10,10 @@ #define CRYINCLUDE_EDITOR_UTILS_REFLECTEDVAR_H #pragma once -#include #include #include #include "Util/VariablePropertyType.h" +#include #include #include #include diff --git a/Code/Editor/EditorPreferencesTreeWidgetItem.cpp b/Code/Editor/EditorPreferencesTreeWidgetItem.cpp index 7adc298c2c..09578e72ee 100644 --- a/Code/Editor/EditorPreferencesTreeWidgetItem.cpp +++ b/Code/Editor/EditorPreferencesTreeWidgetItem.cpp @@ -9,6 +9,9 @@ #include "EditorPreferencesTreeWidgetItem.h" +// AzCore +#include + // AzToolsFramework #include diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp index beb338b732..05477bb0c7 100644 --- a/Code/Editor/MainWindow.cpp +++ b/Code/Editor/MainWindow.cpp @@ -27,10 +27,11 @@ AZ_POP_DISABLE_WARNING #endif // AzCore -#include #include -#include #include +#include +#include +#include #include // AzFramework diff --git a/Code/Editor/PythonEditorFuncs.cpp b/Code/Editor/PythonEditorFuncs.cpp index 455cdfa17d..1b731a3d5f 100644 --- a/Code/Editor/PythonEditorFuncs.cpp +++ b/Code/Editor/PythonEditorFuncs.cpp @@ -18,6 +18,7 @@ #include // AzToolsFramework +#include #include #include diff --git a/Code/Editor/TrackView/TrackViewPythonFuncs.cpp b/Code/Editor/TrackView/TrackViewPythonFuncs.cpp index 72da1e0b18..dc55411f80 100644 --- a/Code/Editor/TrackView/TrackViewPythonFuncs.cpp +++ b/Code/Editor/TrackView/TrackViewPythonFuncs.cpp @@ -19,6 +19,7 @@ // Editor #include "AnimationContext.h" +#include namespace { diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 65d6de8944..0d05e0bf44 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -36,8 +36,9 @@ #include "MathConversion.h" #include "EditorViewportSettings.h" -#include +#include #include +#include #include #include diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManagerComponent.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManagerComponent.cpp index 93315c9c81..b40c36bc6b 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManagerComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManagerComponent.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetSerializer.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetSerializer.cpp index ee594c585b..b5cc6c5df4 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetSerializer.cpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace AZ { diff --git a/Code/Framework/AzCore/AzCore/Component/EntityUtils.h b/Code/Framework/AzCore/AzCore/Component/EntityUtils.h index ce258bc637..5c02a3fe74 100644 --- a/Code/Framework/AzCore/AzCore/Component/EntityUtils.h +++ b/Code/Framework/AzCore/AzCore/Component/EntityUtils.h @@ -5,8 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#ifndef AZCORE_ENTITY_UTILS_H -#define AZCORE_ENTITY_UTILS_H +#pragma once #include #include @@ -217,6 +216,3 @@ namespace AZ } // namespace EntityUtils } // namespace AZ - -#endif // AZCORE_ENTITY_UTILS_H -#pragma once diff --git a/Code/Framework/AzCore/AzCore/Name/NameSerializer.cpp b/Code/Framework/AzCore/AzCore/Name/NameSerializer.cpp index bf3cad7178..581e11ff04 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Name/NameSerializer.cpp @@ -7,6 +7,7 @@ */ #include +#include namespace AZ { diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptProperty.cpp b/Code/Framework/AzCore/AzCore/Script/ScriptProperty.cpp index dbccda4de2..578bbcf271 100644 --- a/Code/Framework/AzCore/AzCore/Script/ScriptProperty.cpp +++ b/Code/Framework/AzCore/AzCore/Script/ScriptProperty.cpp @@ -5,11 +5,13 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ +#include #include #include #include #include #include +#include namespace AZ { diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptProperty.h b/Code/Framework/AzCore/AzCore/Script/ScriptProperty.h index f38931127d..6b7275dfeb 100644 --- a/Code/Framework/AzCore/AzCore/Script/ScriptProperty.h +++ b/Code/Framework/AzCore/AzCore/Script/ScriptProperty.h @@ -5,8 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#ifndef AZCORE_SCRIPT_SCRIPTPROPERTY_H -#define AZCORE_SCRIPT_SCRIPTPROPERTY_H +#pragma once #include #include @@ -490,5 +489,4 @@ namespace AZ }; } -#endif diff --git a/Code/Framework/AzCore/AzCore/Serialization/DataPatch.cpp b/Code/Framework/AzCore/AzCore/Serialization/DataPatch.cpp index 01a98667fa..6f1635148c 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/DataPatch.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/DataPatch.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp index 324df7c141..a741294544 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp @@ -9,6 +9,7 @@ #include "AzCore/RTTI/TypeInfo.h" #include #include +#include #include #include #include diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp index f06fb36be8..8b6c1d154c 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp @@ -6,7 +6,9 @@ * */ +#include #include +#include #include #include #include diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.cpp index 7978b8104b..196ce28216 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.cpp b/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.cpp index 6251a2e6de..746c80f3ea 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.h b/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.h index 5d920045f8..9f9b3fc9f0 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.h +++ b/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.h @@ -37,7 +37,8 @@ namespace AZ class GenericStream; } - namespace ObjectStreamInternal { + namespace ObjectStreamInternal + { class ObjectStreamImpl; } diff --git a/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.cpp b/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.cpp index b74039c876..81546f4f28 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.cpp @@ -7,6 +7,8 @@ */ #include + +#include #include #include #include diff --git a/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.h b/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.h index 3d7f3c00f8..a37780029e 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.h +++ b/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.h @@ -5,8 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#ifndef AZCORE_SERIALIZE_CONTEXT_H -#define AZCORE_SERIALIZE_CONTEXT_H +#pragma once #include @@ -43,6 +42,12 @@ namespace AZ { + namespace Data + { + template + class Asset; + } + class EditContext; class ObjectStream; @@ -2562,11 +2567,13 @@ namespace AZ #include #include -/// include asset generics -#include +// Forward declare asset serialization helper specialization +namespace AZ +{ + template + struct SerializeGenericTypeInfo< Data::Asset >; +} /// include implementation of SerializeContext::EnumBuilder #include -#endif // AZCORE_SERIALIZE_CONTEXT_H -#pragma once diff --git a/Code/Framework/AzCore/AzCore/Slice/SliceComponent.cpp b/Code/Framework/AzCore/AzCore/Slice/SliceComponent.cpp index 82a9175cf9..0b410369f0 100644 --- a/Code/Framework/AzCore/AzCore/Slice/SliceComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Slice/SliceComponent.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfiler.h b/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfiler.h index 2d8823c6e8..681635cd1c 100644 --- a/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfiler.h +++ b/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfiler.h @@ -10,6 +10,7 @@ #include //Just to get AZ::NullMutex #include #include +#include #include namespace AZ @@ -243,7 +244,7 @@ namespace AZ //! This one is needed because running statistics are collected many times across //! several frames. This value is used to calculate a per frame sample for @m_totalTimePerFrameStat, - //! by subtracting @m_prevAccumulatedSums from the accumulated sum in @m_statisticsManager. + //! by subtracting @m_prevAccumulatedSums from the accumulated sum in @m_statisticsManager. double m_prevAccumulatedSums; }; diff --git a/Code/Framework/AzCore/Tests/AZStd/VariantSerialization.cpp b/Code/Framework/AzCore/Tests/AZStd/VariantSerialization.cpp index a87aa70d8c..a4f2d1f1e4 100644 --- a/Code/Framework/AzCore/Tests/AZStd/VariantSerialization.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/VariantSerialization.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index 8ce3747620..caa4cda8f5 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -6,6 +6,7 @@ * */ #include +#include #include #include #include diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerStreamingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerStreamingTests.cpp index a683f9630e..3e9ea42f22 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerStreamingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerStreamingTests.cpp @@ -6,6 +6,7 @@ * */ #include +#include #include #include #include diff --git a/Code/Framework/AzCore/Tests/Asset/BaseAssetManagerTest.cpp b/Code/Framework/AzCore/Tests/Asset/BaseAssetManagerTest.cpp index ba47064998..4dbd3c0e1e 100644 --- a/Code/Framework/AzCore/Tests/Asset/BaseAssetManagerTest.cpp +++ b/Code/Framework/AzCore/Tests/Asset/BaseAssetManagerTest.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp b/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp index e968ee28fc..e04c5190f9 100644 --- a/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp +++ b/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzCore/Tests/AssetManager.cpp b/Code/Framework/AzCore/Tests/AssetManager.cpp index c5f249cf21..1e875d61dc 100644 --- a/Code/Framework/AzCore/Tests/AssetManager.cpp +++ b/Code/Framework/AzCore/Tests/AssetManager.cpp @@ -6,6 +6,7 @@ * */ #include +#include #include #include #include diff --git a/Code/Framework/AzCore/Tests/Serialization.cpp b/Code/Framework/AzCore/Tests/Serialization.cpp index e554945b55..f1d5edc490 100644 --- a/Code/Framework/AzCore/Tests/Serialization.cpp +++ b/Code/Framework/AzCore/Tests/Serialization.cpp @@ -9,6 +9,7 @@ #include "FileIOBaseTestTypes.h" #include +#include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetBundleManifest.h b/Code/Framework/AzFramework/AzFramework/Asset/AssetBundleManifest.h index 9e05263c57..9760482231 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetBundleManifest.h +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetBundleManifest.h @@ -8,7 +8,10 @@ #pragma once -#include +#include +#include +#include +#include namespace AZ { diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetSeedList.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetSeedList.cpp index d16f4bf459..b95efc4dff 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetSeedList.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetSeedList.cpp @@ -8,6 +8,7 @@ */ #include +#include namespace AzFramework { diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetSeedList.h b/Code/Framework/AzFramework/AzFramework/Asset/AssetSeedList.h index 2ad895596b..e982cb54e1 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetSeedList.h +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetSeedList.h @@ -8,7 +8,6 @@ */ #pragma once -#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkAsset.cpp b/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkAsset.cpp index cea1cb1d8e..351eb97245 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkAsset.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkAsset.cpp @@ -7,6 +7,7 @@ */ #include +#include namespace AzFramework { diff --git a/Code/Framework/AzFramework/AzFramework/Asset/SimpleAsset.cpp b/Code/Framework/AzFramework/AzFramework/Asset/SimpleAsset.cpp index 87e603015a..29cfdc5ca7 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/SimpleAsset.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/SimpleAsset.cpp @@ -7,6 +7,7 @@ */ #include +#include #include namespace AzFramework @@ -36,4 +37,36 @@ namespace AzFramework return ""; } + void SimpleAssetReferenceBase::Reflect(AZ::ReflectContext *context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ->Field("AssetPath", &SimpleAssetReferenceBase::m_assetPath); + + AZ::EditContext* edit = serializeContext->GetEditContext(); + if (edit) + { + edit->Class("Asset path", "Asset reference as a project-relative path") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide) + ; + } + } + + if (auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "Asset") + ->Attribute(AZ::Script::Attributes::Module, "asset") + ->Property("assetPath", &SimpleAssetReferenceBase::GetAssetPath, nullptr) + ->Property("assetType", &SimpleAssetReferenceBase::GetAssetType, nullptr) + ->Property("fileFilter", &SimpleAssetReferenceBase::GetFileFilter, nullptr) + ->Method("SetAssetPath", &SimpleAssetReferenceBase::SetAssetPath) + ->Attribute(AZ::Script::Attributes::Alias, "set_asset_path") + ; + } + } } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Asset/SimpleAsset.h b/Code/Framework/AzFramework/AzFramework/Asset/SimpleAsset.h index 7c7a1b4fb2..a7525e90bd 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/SimpleAsset.h +++ b/Code/Framework/AzFramework/AzFramework/Asset/SimpleAsset.h @@ -42,7 +42,6 @@ */ #include -#include #include #include #include @@ -74,38 +73,7 @@ namespace AzFramework virtual AZ::Data::AssetType GetAssetType() const = 0; virtual const char* GetFileFilter() const = 0; - static void Reflect(AZ::ReflectContext* context) - { - if (auto serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Version(1) - ->Field("AssetPath", &SimpleAssetReferenceBase::m_assetPath); - - AZ::EditContext* edit = serializeContext->GetEditContext(); - if (edit) - { - edit->Class("Asset path", "Asset reference as a project-relative path") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide) - ; - } - } - - if (auto behaviorContext = azrtti_cast(context)) - { - behaviorContext->Class() - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) - ->Attribute(AZ::Script::Attributes::Category, "Asset") - ->Attribute(AZ::Script::Attributes::Module, "asset") - ->Property("assetPath", &SimpleAssetReferenceBase::GetAssetPath, nullptr) - ->Property("assetType", &SimpleAssetReferenceBase::GetAssetType, nullptr) - ->Property("fileFilter", &SimpleAssetReferenceBase::GetFileFilter, nullptr) - ->Method("SetAssetPath", &SimpleAssetReferenceBase::SetAssetPath) - ->Attribute(AZ::Script::Attributes::Alias, "set_asset_path") - ; - } - } + static void Reflect(AZ::ReflectContext* context); protected: diff --git a/Code/Framework/AzFramework/AzFramework/Asset/XmlSchemaAsset.h b/Code/Framework/AzFramework/AzFramework/Asset/XmlSchemaAsset.h index 81338d3843..45004fd7cf 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/XmlSchemaAsset.h +++ b/Code/Framework/AzFramework/AzFramework/Asset/XmlSchemaAsset.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Entity/EntityOwnershipServiceBus.h b/Code/Framework/AzFramework/AzFramework/Entity/EntityOwnershipServiceBus.h index a8c0779529..08200afb9e 100644 --- a/Code/Framework/AzFramework/AzFramework/Entity/EntityOwnershipServiceBus.h +++ b/Code/Framework/AzFramework/AzFramework/Entity/EntityOwnershipServiceBus.h @@ -10,6 +10,11 @@ #include +namespace AZ +{ + class Entity; +} + namespace AzFramework { using EntityContextId = AZ::Uuid; diff --git a/Code/Framework/AzFramework/AzFramework/Physics/ClassConverters.cpp b/Code/Framework/AzFramework/AzFramework/Physics/ClassConverters.cpp index 9c1a8c83ca..7e918ee364 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/ClassConverters.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/ClassConverters.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionEvents.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionEvents.cpp index e98bbcc21a..9c1646fa08 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionEvents.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionEvents.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionGroups.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionGroups.cpp index 2100b0c394..13f7dbc672 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionGroups.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionGroups.cpp @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSceneQueries.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSceneQueries.cpp index ff79f097de..28e3762223 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSceneQueries.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSceneQueries.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.cpp index f55c430a2e..4a2a7f99af 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp index 4ac97cf041..222bc48dda 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp @@ -5,6 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + +#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/PhysicsScene.cpp b/Code/Framework/AzFramework/AzFramework/Physics/PhysicsScene.cpp index 62a3916e9e..a5ebdd04c6 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/PhysicsScene.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/PhysicsScene.cpp @@ -9,6 +9,7 @@ #include #include +#include namespace AzPhysics diff --git a/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.cpp b/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.cpp index 2fda459e20..2ff4780c9e 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.cpp @@ -8,6 +8,8 @@ #include +#include + namespace AzPhysics { void SystemInterface::Reflect(AZ::ReflectContext* context) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Shape.h b/Code/Framework/AzFramework/AzFramework/Physics/Shape.h index 6549269c77..0a766473e1 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Shape.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Shape.h @@ -9,7 +9,6 @@ #pragma once #include -#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp index ab5cb90616..e90c9d4eed 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp @@ -7,9 +7,11 @@ */ #include +#include #include #include #include +#include namespace Physics { diff --git a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h index 07845e95b9..b40a8b1edd 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h @@ -10,6 +10,7 @@ #include #include +#include #include namespace Physics diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp index 81af7b5840..3dcb37c541 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp @@ -10,12 +10,14 @@ #include "Utils.h" #include "Material.h" #include "Shape.h" + +#include +#include #include #include #include #include #include -#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp b/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp index e11dc6dace..bfd7c5ac4c 100644 --- a/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp index cb1e657edd..f6130c9e31 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/StreamingInstall/StreamingInstall.cpp b/Code/Framework/AzFramework/AzFramework/StreamingInstall/StreamingInstall.cpp index e1e193abfd..e90dcc17a1 100644 --- a/Code/Framework/AzFramework/AzFramework/StreamingInstall/StreamingInstall.cpp +++ b/Code/Framework/AzFramework/AzFramework/StreamingInstall/StreamingInstall.cpp @@ -7,6 +7,7 @@ */ #include +#include #include "StreamingInstall.h" namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/StreamingInstall/StreamingInstallRequests.h b/Code/Framework/AzFramework/AzFramework/StreamingInstall/StreamingInstallRequests.h index dba2a78f3c..201f9007c5 100644 --- a/Code/Framework/AzFramework/AzFramework/StreamingInstall/StreamingInstallRequests.h +++ b/Code/Framework/AzFramework/AzFramework/StreamingInstall/StreamingInstallRequests.h @@ -9,10 +9,8 @@ #pragma once #include -#include #include #include -#include namespace AzFramework { diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/ISerializer.inl b/Code/Framework/AzNetworking/AzNetworking/Serialization/ISerializer.inl index 0d705629f3..56cbb52049 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/ISerializer.inl +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/ISerializer.inl @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Gallery/ReflectedPropertyEditorPage.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Gallery/ReflectedPropertyEditorPage.cpp index 7655a2076c..2be0428d63 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Gallery/ReflectedPropertyEditorPage.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Gallery/ReflectedPropertyEditorPage.cpp @@ -9,6 +9,7 @@ #include "ReflectedPropertyEditorPage.h" #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorEntityAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorEntityAPI.h index f2808eb0e7..3b5e5c9dc3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorEntityAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorEntityAPI.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index 91a916ae70..717e0c6f8a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp index 5a1e491b01..cc3153ed8e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include namespace AzToolsFramework { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp index ee3669a7ba..7083737cf7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.cpp new file mode 100644 index 0000000000..43c950cd00 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.cpp @@ -0,0 +1,24 @@ +/* + * 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 "AssetEditorBus.h" +#include +#include + +namespace AzToolsFramework::AssetEditor +{ + void AssetEditorWindowSettings::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Field("m_openAssets", &AssetEditorWindowSettings::m_openAssets) + ; + } + } +} // namespace AzToolsFramework::AssetEditor diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.h index 4d14e5c1bf..becdba44ea 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.h @@ -8,12 +8,14 @@ #pragma once #include +#include #include -#include #include -#include -namespace AZ { namespace Data { class AssetData; } } +namespace AZ::Data +{ + class AssetData; +} namespace AZStd { @@ -45,15 +47,7 @@ namespace AzToolsFramework static constexpr const char* s_name = "AssetEditorWindowSettings"; - static void Reflect(AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Field("m_openAssets", &AssetEditorWindowSettings::m_openAssets) - ; - } - } + static void Reflect(AZ::ReflectContext* context); }; // External interaction with Asset Editor diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp index 95dc0f36c4..e09dd183f8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp @@ -22,6 +22,7 @@ AZ_POP_DISABLE_WARNING #include #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp index 6ed133c830..7789070209 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/EditorPrefabComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/EditorPrefabComponent.cpp index 7aa5967a44..d95a704e84 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/EditorPrefabComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/EditorPrefabComponent.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/EditorPrefabComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/EditorPrefabComponent.h index 75b68c859d..8873787bd3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/EditorPrefabComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/EditorPrefabComponent.h @@ -8,7 +8,6 @@ #pragma once #include -#include namespace AzToolsFramework { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicRequestHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicRequestHandler.cpp index ad171dc6f4..0aaf81c4c9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicRequestHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicRequestHandler.cpp @@ -10,6 +10,8 @@ #include +#include + namespace AzToolsFramework { namespace Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.cpp index 8e0d7fcd42..ac3ada7557 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/PropertyTreeEditor/PropertyTreeEditor.h b/Code/Framework/AzToolsFramework/AzToolsFramework/PropertyTreeEditor/PropertyTreeEditor.h index 7e416c3cc0..648a39fe76 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/PropertyTreeEditor/PropertyTreeEditor.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/PropertyTreeEditor/PropertyTreeEditor.h @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp index cca0071a4d..f58f273f11 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp @@ -7,6 +7,7 @@ */ #include "EditorLayerComponent.h" #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ScriptEditorComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ScriptEditorComponent.cpp index cc350c8107..be29af5c0f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ScriptEditorComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ScriptEditorComponent.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp index c07191fda2..ba84e662c1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp @@ -33,6 +33,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx index 33619f9f62..cc4aff5649 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx @@ -16,6 +16,7 @@ #include #include "PropertyEditorAPI.h" #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 88febef8c2..209eadf59e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -7,6 +7,7 @@ # set(FILES + AssetEditor/AssetEditorBus.cpp AssetEditor/AssetEditorBus.h AssetEditor/AssetEditorToolbar.ui AssetEditor/AssetEditorStatusBar.ui diff --git a/Code/Framework/AzToolsFramework/Tests/PropertyTreeEditorTests.cpp b/Code/Framework/AzToolsFramework/Tests/PropertyTreeEditorTests.cpp index 91e53f1650..5def9e6bad 100644 --- a/Code/Framework/AzToolsFramework/Tests/PropertyTreeEditorTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/PropertyTreeEditorTests.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Code/Legacy/CryCommon/Maestro/Bus/SequenceComponentBus.h b/Code/Legacy/CryCommon/Maestro/Bus/SequenceComponentBus.h index ba3d7bdcb6..9a3619b89e 100644 --- a/Code/Legacy/CryCommon/Maestro/Bus/SequenceComponentBus.h +++ b/Code/Legacy/CryCommon/Maestro/Bus/SequenceComponentBus.h @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include #include diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp index d6c4661c15..62b063c83b 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp @@ -20,6 +20,7 @@ #include #include #include // For slice asset sub ids +#include ////////////////////////////////////////////////////////////////////////// namespace AssetBuilderSDK diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/SerializationDependencies.cpp b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/SerializationDependencies.cpp index 9e826faabb..09c6fc7cb4 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/SerializationDependencies.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/SerializationDependencies.cpp @@ -7,6 +7,7 @@ */ #include +#include namespace AssetBuilderSDK { diff --git a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp index f570a1ccb4..6eee3d6f2b 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp @@ -8,6 +8,7 @@ #include "native/AssetManager/AssetCatalog.h" +#include #include #include #include diff --git a/Code/Tools/AssetProcessor/native/AssetManager/AssetRequestHandler.cpp b/Code/Tools/AssetProcessor/native/AssetManager/AssetRequestHandler.cpp index 60873ae1af..c3530c768a 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/AssetRequestHandler.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/AssetRequestHandler.cpp @@ -8,9 +8,10 @@ #include "AssetRequestHandler.h" +#include +#include #include #include -#include using namespace AssetProcessor; diff --git a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp index e6d9894116..c65ab24aed 100644 --- a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp +++ b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/Code/Tools/AssetProcessor/native/tests/assetBuilderSDK/SerializationDependenciesTests.cpp b/Code/Tools/AssetProcessor/native/tests/assetBuilderSDK/SerializationDependenciesTests.cpp index 86c363075d..71d11b19eb 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetBuilderSDK/SerializationDependenciesTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetBuilderSDK/SerializationDependenciesTests.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include diff --git a/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpBlendShapeImporter.cpp b/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpBlendShapeImporter.cpp index 8e447f9d79..2dd7fff8e2 100644 --- a/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpBlendShapeImporter.cpp +++ b/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpBlendShapeImporter.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/Code/Tools/SceneAPI/SceneCore/Containers/GraphObjectProxy.h b/Code/Tools/SceneAPI/SceneCore/Containers/GraphObjectProxy.h index 5b6178a63d..ded12e4051 100644 --- a/Code/Tools/SceneAPI/SceneCore/Containers/GraphObjectProxy.h +++ b/Code/Tools/SceneAPI/SceneCore/Containers/GraphObjectProxy.h @@ -12,6 +12,10 @@ namespace AZ { + struct BehaviorParameter; + struct BehaviorValueParameter; + class BehaviorClass; + namespace Python { class PythonBehaviorInfo; diff --git a/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.cpp b/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.cpp index d68b6c52d4..664c5f1272 100644 --- a/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Tools/SceneAPI/SceneCore/DllMain.cpp b/Code/Tools/SceneAPI/SceneCore/DllMain.cpp index 408b516f84..ad875f5538 100644 --- a/Code/Tools/SceneAPI/SceneCore/DllMain.cpp +++ b/Code/Tools/SceneAPI/SceneCore/DllMain.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include diff --git a/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp b/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp index 8924f10115..2e6503d195 100644 --- a/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp +++ b/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp index fa81ea2826..066129f974 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp +++ b/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace AZ { diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp index 117a1196f8..b6b87fecc7 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp +++ b/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Gems/AWSCore/Code/Source/AWSCoreSystemComponent.cpp b/Gems/AWSCore/Code/Source/AWSCoreSystemComponent.cpp index 92a5aa493f..294462e654 100644 --- a/Gems/AWSCore/Code/Source/AWSCoreSystemComponent.cpp +++ b/Gems/AWSCore/Code/Source/AWSCoreSystemComponent.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include diff --git a/Gems/AWSCore/Code/Tests/AWSCoreSystemComponentTest.cpp b/Gems/AWSCore/Code/Tests/AWSCoreSystemComponentTest.cpp index 730fc97f49..f9fff631f4 100644 --- a/Gems/AWSCore/Code/Tests/AWSCoreSystemComponentTest.cpp +++ b/Gems/AWSCore/Code/Tests/AWSCoreSystemComponentTest.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/AWSCore/Code/Tests/Editor/AWSCoreEditorSystemComponentTest.cpp b/Gems/AWSCore/Code/Tests/Editor/AWSCoreEditorSystemComponentTest.cpp index 07a6c8ae08..0cd01b4245 100644 --- a/Gems/AWSCore/Code/Tests/Editor/AWSCoreEditorSystemComponentTest.cpp +++ b/Gems/AWSCore/Code/Tests/Editor/AWSCoreEditorSystemComponentTest.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp index 4f178f4655..a6cb024ba8 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp @@ -6,11 +6,12 @@ * */ +#include + +#include #include #include -#include - namespace AWSGameLift { void AWSGameLiftCreateSessionOnQueueRequest::Reflect(AZ::ReflectContext* context) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionRequest.cpp index 4e21c0e711..1c9669e474 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionRequest.cpp @@ -6,11 +6,12 @@ * */ +#include + +#include #include #include -#include - namespace AWSGameLift { void AWSGameLiftCreateSessionRequest::Reflect(AZ::ReflectContext* context) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftJoinSessionRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftJoinSessionRequest.cpp index 4007093175..7d23a4b581 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftJoinSessionRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftJoinSessionRequest.cpp @@ -5,12 +5,12 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ +#include +#include #include #include -#include - namespace AWSGameLift { void AWSGameLiftJoinSessionRequest::Reflect(AZ::ReflectContext* context) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftSearchSessionsRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftSearchSessionsRequest.cpp index f484a0b357..b78320dc32 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftSearchSessionsRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftSearchSessionsRequest.cpp @@ -6,13 +6,14 @@ * */ +#include +#include + +#include #include #include #include -#include -#include - namespace AWSGameLift { void AWSGameLiftSearchSessionsRequest::Reflect(AZ::ReflectContext* context) diff --git a/Gems/Atom/Component/DebugCamera/Code/Source/ArcBallControllerComponent.cpp b/Gems/Atom/Component/DebugCamera/Code/Source/ArcBallControllerComponent.cpp index 040338ab6f..904d6e0c2f 100644 --- a/Gems/Atom/Component/DebugCamera/Code/Source/ArcBallControllerComponent.cpp +++ b/Gems/Atom/Component/DebugCamera/Code/Source/ArcBallControllerComponent.cpp @@ -9,6 +9,7 @@ #include +#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshVertexStreams.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshVertexStreams.h index 5be3bece5e..aedfb73396 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshVertexStreams.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshVertexStreams.h @@ -8,7 +8,6 @@ #pragma once -#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp index a9ee46dd2c..9e29070e71 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp @@ -7,6 +7,7 @@ */ +#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index 4d437be244..5b90ed7f06 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -7,6 +7,8 @@ */ #include +#include +#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp index 36c604c931..8984747b74 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp @@ -9,6 +9,7 @@ #undef RC_INVOKED #include +#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp index 156fca3b7e..c684b3cc89 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp @@ -9,8 +9,11 @@ #undef RC_INVOKED #include +#include #include #include +#include +#include namespace AZ { diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Handle.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Handle.h index 01e1fab7cc..3e0c3335a0 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Handle.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Handle.h @@ -9,6 +9,7 @@ #include #include +#include namespace AZ { diff --git a/Gems/Atom/RHI/Code/Source/RHI.Reflect/ShaderSemantic.cpp b/Gems/Atom/RHI/Code/Source/RHI.Reflect/ShaderSemantic.cpp index 3cb4bd05a5..718604d750 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Reflect/ShaderSemantic.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Reflect/ShaderSemantic.cpp @@ -7,6 +7,8 @@ */ #include + +#include #include #include #include diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h index a19c985f2d..b94d2169bf 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h @@ -24,6 +24,8 @@ namespace AZ { namespace RPI { + class ModelAsset; + class Model final : public Data::InstanceData { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantListSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantListSourceData.cpp index b6a2132b89..6cd38f65bc 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantListSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantListSourceData.cpp @@ -8,9 +8,10 @@ #include #include - +#include #include + namespace AZ { namespace RPI diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp index 50da470ec4..1ba17deb91 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp @@ -7,6 +7,7 @@ */ #include +#include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLodUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLodUtils.cpp index a1651defbc..3cbb20b9e9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLodUtils.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLodUtils.cpp @@ -10,7 +10,9 @@ #include #include +#include +#include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp index 1ed81f8e16..775d02f7ab 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAsset.cpp index 180ce6d5a7..95f47d7393 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAsset.cpp @@ -8,6 +8,7 @@ #include +#include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetView.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetView.cpp index a88d4f10e4..2b3aabdba2 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetView.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetView.cpp @@ -7,6 +7,7 @@ */ #include +#include namespace AZ { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImageAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImageAsset.cpp index 1caba9dba8..59f359e474 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImageAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImageAsset.cpp @@ -8,6 +8,7 @@ #include +#include #include namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImagePoolAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImagePoolAsset.cpp index fda4c31b08..056002f527 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImagePoolAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImagePoolAsset.cpp @@ -9,6 +9,7 @@ #include #include +#include namespace AZ { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp index 9338d52cb2..c33409f687 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp index c3e0221192..5c7af601fb 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyValue.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyValue.cpp index 13ecea52dc..d1017139fc 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyValue.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyValue.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp index 7b3b6b7a28..87076891dd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp index 8e2d1bdd7e..9a432643d7 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp index b9d9200aaf..4485359cf9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/MorphTargetMetaAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/MorphTargetMetaAsset.cpp index 228ef67025..bcdc91abda 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/MorphTargetMetaAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/MorphTargetMetaAsset.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp index 49ef457311..692087d93b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h index a8ef7852ea..6a21a8a2df 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace AtomToolsFramework { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp index e1f8573bb3..86ac4a3df1 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace AtomToolsFramework { diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp index 7571738597..932e2e7436 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include 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 d4269c2438..04c53457ae 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/Utils.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/Utils.h index 73a61b2345..25b96319c5 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/Utils.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/Utils.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/AttachmentComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/AttachmentComponent.cpp index ac37e293b9..ee66518779 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/AttachmentComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/AttachmentComponent.cpp @@ -6,6 +6,7 @@ * */ #include "AttachmentComponent.h" +#include #include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/EditorAttachmentComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/EditorAttachmentComponent.cpp index 878eb51efb..b10a3e6695 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/EditorAttachmentComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/EditorAttachmentComponent.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.cpp index 49b31388ad..5d16164d92 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp index 8aec22e22c..8b864613c4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp index 013a8ee1b4..7f676e4c10 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ImageBasedLights/ImageBasedLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ImageBasedLights/ImageBasedLightComponentConfig.cpp index c98d5be5ef..8ddd727076 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ImageBasedLights/ImageBasedLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ImageBasedLights/ImageBasedLightComponentConfig.cpp @@ -7,6 +7,7 @@ */ #include +#include #include namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index 363221d3fc..c4d21ba599 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 1d9f1e81dd..bd148c8ba4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -142,7 +143,7 @@ namespace AZ { InitializeMaterialInstance(asset); } - + void MaterialComponentController::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { AZStd::unordered_set propertyOverrides; @@ -193,7 +194,7 @@ namespace AZ materialInstance->Compile(); } - // Only disconnect from tick bus and send notification after all pending properties have been applied + // Only disconnect from tick bus and send notification after all pending properties have been applied if (m_queuedPropertyOverrides.empty()) { if (m_queuedMaterialUpdateNotification) @@ -229,7 +230,7 @@ namespace AZ ReleaseMaterials(); } } - + void MaterialComponentController::InitializeMaterialInstance(const Data::Asset& asset) { bool allReady = true; @@ -334,7 +335,7 @@ namespace AZ // this function is called twice once material asset is changed, a temp variable is // needed to prevent material asset going out of scope during second call // before LoadMaterials() is called [LYN-2249] - auto temp = m_configuration.m_materials; + auto temp = m_configuration.m_materials; m_configuration.m_materials = materials; LoadMaterials(); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 9e0c285001..2dc3b9134a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentConfig.cpp index 9c137f5b72..f9a427a3a0 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentConfig.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp index d06bc981fe..e10a8b14c9 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp @@ -6,9 +6,10 @@ * */ -#include #include #include +#include +#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponent.cpp index d38130bef6..3318f84905 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponent.cpp @@ -8,6 +8,8 @@ #include +#include + namespace AZ { namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentConfig.cpp index f77f67635f..4b1665895f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentConfig.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentController.cpp index aedb25bb36..4f321ed8b1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentController.cpp @@ -7,6 +7,7 @@ */ #include +#include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/RadiusWeightModifierComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/RadiusWeightModifierComponent.cpp index 53b508c619..d668533807 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/RadiusWeightModifierComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/RadiusWeightModifierComponent.cpp @@ -8,6 +8,8 @@ #include +#include + namespace AZ { namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/ShapeWeightModifierComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/ShapeWeightModifierComponent.cpp index fd3063fe98..bc3f6f8719 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/ShapeWeightModifierComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/ShapeWeightModifierComponent.cpp @@ -8,6 +8,8 @@ #include +#include + namespace AZ { namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/ShapeWeightModifierComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/ShapeWeightModifierComponentController.cpp index 42898cd188..d4761efa96 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/ShapeWeightModifierComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/ShapeWeightModifierComponentController.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp index aa68333108..d7fcd124d0 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp index 764741a5cf..4022dfda9b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/HDRiSkyboxComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/HDRiSkyboxComponentConfig.cpp index b86cccf341..288892cddf 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/HDRiSkyboxComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/HDRiSkyboxComponentConfig.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include diff --git a/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp b/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp index c2fb81e86a..8c6c0a8e05 100644 --- a/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -208,7 +209,7 @@ namespace Blast itr.second.Disconnect(); } m_collisionHandlers.clear(); - + BlastFamilyDamageRequestBus::MultiHandler::BusDisconnect(); BlastFamilyComponentRequestBus::Handler::BusDisconnect(); @@ -546,7 +547,7 @@ namespace Blast } m_solver->notifyActorCreated(*actor.GetTkActor().getActorLL()); - + if (auto* physicsSystem = AZ::Interface::Get()) { AZStd::pair foundBody = physicsSystem->FindAttachedBodyHandleFromEntityId(actor.GetEntity()->GetId()); diff --git a/Gems/Blast/Code/Source/Components/BlastMeshDataComponent.cpp b/Gems/Blast/Code/Source/Components/BlastMeshDataComponent.cpp index 17848a53d3..a9f079dd65 100644 --- a/Gems/Blast/Code/Source/Components/BlastMeshDataComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastMeshDataComponent.cpp @@ -7,6 +7,7 @@ */ #include +#include #include namespace Blast diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp index 851cb4460b..0c697f12b6 100644 --- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp b/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp index 3bc6da4297..90f530895a 100644 --- a/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp +++ b/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp b/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp index 9d0e4fe2ff..83085b5f9c 100644 --- a/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp +++ b/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphFollowerParameterAction.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphFollowerParameterAction.cpp index 1355e2b0e5..3d8add320a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphFollowerParameterAction.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphFollowerParameterAction.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphReferenceNode.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphReferenceNode.cpp index 605810c5cc..16f192615d 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphReferenceNode.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphReferenceNode.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphSymbolicFollowerParameterAction.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphSymbolicFollowerParameterAction.cpp index fda679b8d0..e1f15c1ab2 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphSymbolicFollowerParameterAction.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphSymbolicFollowerParameterAction.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp index da4c72b70a..ab55f909c2 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/AnimGraphComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/AnimGraphComponent.cpp index 704b746e3f..c47c18ba7d 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/AnimGraphComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/AnimGraphComponent.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/SimpleMotionComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/SimpleMotionComponent.cpp index dd7fdeea50..6876051c63 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/SimpleMotionComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/SimpleMotionComponent.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp index ed4edda891..94e52a172f 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorAnimGraphComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorAnimGraphComponent.cpp index 8721acbf3d..9833fcc87a 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorAnimGraphComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorAnimGraphComponent.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp b/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp index acdd78fc0f..0155b38da2 100644 --- a/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp +++ b/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonAssetTypesTests.cpp b/Gems/EditorPythonBindings/Code/Tests/PythonAssetTypesTests.cpp index 9940a01b7a..688eff7671 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonAssetTypesTests.cpp +++ b/Gems/EditorPythonBindings/Code/Tests/PythonAssetTypesTests.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp b/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp index 8d472945cc..f68bef1c93 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp +++ b/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include diff --git a/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp index 9e01b690e0..6fe8d32484 100644 --- a/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp @@ -8,6 +8,7 @@ #include "ImageGradientComponent.h" #include +#include #include #include #include diff --git a/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp b/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp index fbd7bdfd22..a461866c46 100644 --- a/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp +++ b/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp @@ -8,6 +8,8 @@ #include +#include + #include #include diff --git a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYEntityOutliner.cpp b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYEntityOutliner.cpp index 2df6c9984b..1bf9d26fdf 100644 --- a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYEntityOutliner.cpp +++ b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYEntityOutliner.cpp @@ -11,6 +11,7 @@ #ifdef IMGUI_ENABLED #include +#include #include #include #include diff --git a/Gems/LmbrCentral/Code/Source/Builders/LuaBuilder/LuaBuilderWorker.h b/Gems/LmbrCentral/Code/Source/Builders/LuaBuilder/LuaBuilderWorker.h index 1d3a61626b..6f2aeecb8f 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/LuaBuilder/LuaBuilderWorker.h +++ b/Gems/LmbrCentral/Code/Source/Builders/LuaBuilder/LuaBuilderWorker.h @@ -7,10 +7,14 @@ */ #pragma once -#include -#include #include #include +#include +#include +namespace AZ +{ + class ScriptContext; +} namespace LuaBuilder { @@ -39,6 +43,10 @@ namespace LuaBuilder JobStepOutcome RunCompileJob(const AssetBuilderSDK::ProcessJobRequest& request); JobStepOutcome RunCopyJob(const AssetBuilderSDK::ProcessJobRequest& request); - JobStepOutcome WriteAssetInfo(const AssetBuilderSDK::ProcessJobRequest& request, AZStd::string_view destFileName, AZStd::string_view debugName, AZ::ScriptContext& scriptContext); + JobStepOutcome WriteAssetInfo( + const AssetBuilderSDK::ProcessJobRequest& request, + AZStd::string_view destFileName, + AZStd::string_view debugName, + AZ::ScriptContext& scriptContext); }; -} +} // namespace LuaBuilder diff --git a/Gems/LmbrCentral/Code/Source/Scripting/EditorSpawnerComponent.cpp b/Gems/LmbrCentral/Code/Source/Scripting/EditorSpawnerComponent.cpp index 315480c869..f43b69f703 100644 --- a/Gems/LmbrCentral/Code/Source/Scripting/EditorSpawnerComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Scripting/EditorSpawnerComponent.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include diff --git a/Gems/LmbrCentral/Code/Source/Scripting/SpawnerComponent.cpp b/Gems/LmbrCentral/Code/Source/Scripting/SpawnerComponent.cpp index 5305a68d84..f79dc3f598 100644 --- a/Gems/LmbrCentral/Code/Source/Scripting/SpawnerComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Scripting/SpawnerComponent.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff --git a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp index 647a5dedef..73ef7143c8 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/LyShine/Code/Source/UiSpawnerComponent.cpp b/Gems/LyShine/Code/Source/UiSpawnerComponent.cpp index e9e4e4539f..6eb04b3684 100644 --- a/Gems/LyShine/Code/Source/UiSpawnerComponent.cpp +++ b/Gems/LyShine/Code/Source/UiSpawnerComponent.cpp @@ -7,6 +7,7 @@ */ #include "UiSpawnerComponent.h" +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index 634cac74b2..7b7cb52fe1 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index e66eb8d3a3..023c5ea3af 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp index 5d677c6101..198deebbe3 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponent.cpp b/Gems/NvCloth/Code/Source/Components/ClothComponent.cpp index 0bbe52faf1..b252d3b5e6 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponent.cpp +++ b/Gems/NvCloth/Code/Source/Components/ClothComponent.cpp @@ -8,6 +8,7 @@ #include #include +#include #include diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp index ecf2bd0a54..9a211290e3 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp +++ b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp @@ -27,6 +27,9 @@ #include #include #include +#include +#include +#include namespace NvCloth { diff --git a/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp b/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp index 113d660b32..420c6f3a5c 100644 --- a/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp +++ b/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include diff --git a/Gems/NvCloth/Code/Source/Editor/MeshNodeHandler.cpp b/Gems/NvCloth/Code/Source/Editor/MeshNodeHandler.cpp index d42277ebb4..9f874f7765 100644 --- a/Gems/NvCloth/Code/Source/Editor/MeshNodeHandler.cpp +++ b/Gems/NvCloth/Code/Source/Editor/MeshNodeHandler.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include diff --git a/Gems/NvCloth/Code/Source/Editor/MeshNodeHandler.h b/Gems/NvCloth/Code/Source/Editor/MeshNodeHandler.h index 76161aa838..be4ac2ae36 100644 --- a/Gems/NvCloth/Code/Source/Editor/MeshNodeHandler.h +++ b/Gems/NvCloth/Code/Source/Editor/MeshNodeHandler.h @@ -10,6 +10,7 @@ #if !defined(Q_MOC_RUN) #include +#include #include #include #endif diff --git a/Gems/NvCloth/Code/Source/Utils/MeshAssetHelper.cpp b/Gems/NvCloth/Code/Source/Utils/MeshAssetHelper.cpp index c95c8896ab..b72a5594e8 100644 --- a/Gems/NvCloth/Code/Source/Utils/MeshAssetHelper.cpp +++ b/Gems/NvCloth/Code/Source/Utils/MeshAssetHelper.cpp @@ -7,6 +7,7 @@ */ #include +#include #include diff --git a/Gems/PhysX/Code/Editor/EditorClassConverters.cpp b/Gems/PhysX/Code/Editor/EditorClassConverters.cpp index e55ac6bbda..c9f5626dab 100644 --- a/Gems/PhysX/Code/Editor/EditorClassConverters.cpp +++ b/Gems/PhysX/Code/Editor/EditorClassConverters.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 566903d84a..7c07ca207c 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp index bb32f707be..4a4f12558d 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.cpp b/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.cpp index 7d3096a6da..ab6770c3fe 100644 --- a/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.cpp +++ b/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.cpp @@ -7,6 +7,7 @@ */ #include "PrefabBuilderTests.h" +#include #include #include #include diff --git a/Gems/PythonAssetBuilder/Code/Source/PythonBuilderNotificationHandler.h b/Gems/PythonAssetBuilder/Code/Source/PythonBuilderNotificationHandler.h index 669ef21914..099bc9d587 100644 --- a/Gems/PythonAssetBuilder/Code/Source/PythonBuilderNotificationHandler.h +++ b/Gems/PythonAssetBuilder/Code/Source/PythonBuilderNotificationHandler.h @@ -9,6 +9,7 @@ #include #include +#include namespace PythonAssetBuilder { diff --git a/Gems/PythonAssetBuilder/Code/Source/PythonBuilderWorker.cpp b/Gems/PythonAssetBuilder/Code/Source/PythonBuilderWorker.cpp index 0e05c5e7bf..f06b4a22d7 100644 --- a/Gems/PythonAssetBuilder/Code/Source/PythonBuilderWorker.cpp +++ b/Gems/PythonAssetBuilder/Code/Source/PythonBuilderWorker.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -56,7 +57,7 @@ namespace PythonAssetBuilder { this->ProcessJob(request, response); }; - + // connect to the shutdown signal handler AssetBuilderCommandBus::Handler::BusConnect(m_assetBuilderDesc->m_busId); diff --git a/Gems/SceneProcessing/Code/Source/Config/Components/SceneProcessingConfigSystemComponent.cpp b/Gems/SceneProcessing/Code/Source/Config/Components/SceneProcessingConfigSystemComponent.cpp index ea0c3520bf..281def11b5 100644 --- a/Gems/SceneProcessing/Code/Source/Config/Components/SceneProcessingConfigSystemComponent.cpp +++ b/Gems/SceneProcessing/Code/Source/Config/Components/SceneProcessingConfigSystemComponent.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index 9c3cdca3e8..3c168855d8 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace ScriptCanvasBuilderCpp { diff --git a/Gems/ScriptCanvas/Code/Editor/Settings.h b/Gems/ScriptCanvas/Code/Editor/Settings.h index 7eff40ec43..eefb7454c3 100644 --- a/Gems/ScriptCanvas/Code/Editor/Settings.h +++ b/Gems/ScriptCanvas/Code/Editor/Settings.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h index 2b53cf9fd5..cbb8ef12d6 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp index e708efc71f..0dcd8ebbbd 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp @@ -9,6 +9,7 @@ #include "RuntimeAsset.h" #include +#include namespace ScriptCanvasRuntimeAssetCpp { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Source.jinja b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Source.jinja index 64e92c1ac7..1ddffe3de9 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Source.jinja +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Source.jinja @@ -14,6 +14,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT {% endmacro %} #include #include +#include #include #include diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja index 236866ffeb..f80c932735 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja @@ -15,6 +15,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include #include #include #include diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.cpp index 6cda0b75dd..542fc2f0c1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.cpp @@ -14,6 +14,7 @@ #include #include +#include namespace FunctionDefinitionNodeCpp { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersionConverters.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersionConverters.cpp index 2998b3c2ee..23e4a8cc7a 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersionConverters.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersionConverters.cpp @@ -7,6 +7,7 @@ */ #include "VersionConverters.h" +#include #include #include diff --git a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp index 5b38b640ca..cba14feac6 100644 --- a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp +++ b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/Gems/ScriptCanvasTesting/Code/Source/Nodes/BehaviorContextObjectTestNode.h b/Gems/ScriptCanvasTesting/Code/Source/Nodes/BehaviorContextObjectTestNode.h index 2093912dd9..cc7bda1c95 100644 --- a/Gems/ScriptCanvasTesting/Code/Source/Nodes/BehaviorContextObjectTestNode.h +++ b/Gems/ScriptCanvasTesting/Code/Source/Nodes/BehaviorContextObjectTestNode.h @@ -10,6 +10,9 @@ #include +#include +#include + namespace ScriptCanvasTestingNodes { //! This object is used to test the use of BehaviorContext classes diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventBroadcast.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventBroadcast.h index de2563c6ad..d29bf5910c 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventBroadcast.h +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventBroadcast.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include @@ -38,8 +39,8 @@ namespace ScriptEvents void ReserveArguments(size_t numArguments); - size_t GetNumArguments() const override { return m_behaviorParameters.size(); } - const AZ::BehaviorParameter* GetArgument(size_t index) const override + size_t GetNumArguments() const override { return m_behaviorParameters.size(); } + const AZ::BehaviorParameter* GetArgument(size_t index) const override { if (index >= m_behaviorParameters.size()) { diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventMethod.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventMethod.h index 0ff8194e56..a0893417fc 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventMethod.h +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventMethod.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include @@ -38,8 +39,8 @@ namespace ScriptEvents void ReserveArguments(size_t numArguments); - size_t GetNumArguments() const override { return m_behaviorParameters.size(); } - const AZ::BehaviorParameter* GetArgument(size_t index) const override + size_t GetNumArguments() const override { return m_behaviorParameters.size(); } + const AZ::BehaviorParameter* GetArgument(size_t index) const override { if (index >= m_behaviorParameters.size()) { @@ -47,7 +48,7 @@ namespace ScriptEvents return nullptr; } - return &m_behaviorParameters[index]; + return &m_behaviorParameters[index]; } const AZStd::string* GetArgumentName(size_t index) const override { return &m_argumentNames[index]; } diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventMethod.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventMethod.h index a04b5969bf..77f8d1cbd4 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventMethod.h +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventMethod.h @@ -9,10 +9,12 @@ #pragma once #include -#include -#include #include +namespace AZ +{ + class ReflectContext; +} namespace ScriptEvents { //! Holds the versioned definition for each of a script events. @@ -21,7 +23,6 @@ namespace ScriptEvents class Method { public: - AZ_TYPE_INFO(Method, "{E034EA83-C798-413D-ACE8-4923C51CF4F7}"); Method() @@ -67,29 +68,7 @@ namespace ScriptEvents FromScript(dc); } - void FromScript(AZ::ScriptDataContext& dc) - { - if (dc.GetNumArguments() > 0) - { - AZStd::string name; - if (dc.IsString(0) && dc.ReadArg(0, name)) - { - m_name.Set(name.c_str()); - } - - if (dc.GetNumArguments() > 1) - { - AZ::Uuid returnType; - if (dc.ReadArg(1, returnType)) - { - m_returnType.Set(returnType); - } - } - } - - //AZ_TracePrintf("Script Events", "Added Script Method: %s (return type: %s)\n", GetName().c_str(), m_returnType.IsEmpty() ? "none" : GetReturnType().ToString().c_str()); - - } + void FromScript(AZ::ScriptDataContext& dc); ~Method() { @@ -111,150 +90,71 @@ namespace ScriptEvents return m_parameters.back(); } - static void Reflect(AZ::ReflectContext* context) + static void Reflect(AZ::ReflectContext* context); + + AZStd::string GetName() const { - if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Field("m_name", &Method::m_name) - ->Field("m_tooltip", &Method::m_tooltip) - ->Field("m_returnType", &Method::m_returnType) - ->Field("m_parameters", &Method::m_parameters) - ; - - if (AZ::EditContext* editContext = serializeContext->GetEditContext()) - { - editContext->Class("Script Event", "A script event's definition") - ->DataElement(AZ::Edit::UIHandlers::Default, &Method::m_name, "Name", "The specified name for this event, represents a callable function (i.e. MyScriptEvent())") - ->DataElement(AZ::Edit::UIHandlers::Default, &Method::m_tooltip, "Tooltip", "A description of this event") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &Method::m_returnType, "Return value type", "the typeid of the return value, ex. AZ::type_info::Uuid foo()") - ->Attribute(AZ::Edit::Attributes::GenericValueList, &Types::GetValidReturnTypes) - ->DataElement(AZ::Edit::UIHandlers::Default, &Method::m_parameters, "Parameters", "A list of parameters for the EBus event, ex. void foo(Parameter1, Parameter2)") - ; - } - } - - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) - { - behaviorContext->Class("Method") - ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) - ->Method("AddParameter", &Method::AddParameter) - ->Property("Name", BehaviorValueProperty(&Method::m_name)) - ->Property("ReturnType", BehaviorValueProperty(&Method::m_returnType)) - ->Property("Parameters", BehaviorValueProperty(&Method::m_parameters)) - ; - } + return m_name.Get() ? *m_name.Get() : ""; + } + AZStd::string GetTooltip() const + { + return m_tooltip.Get() ? *m_tooltip.Get() : ""; } - AZStd::string GetName() const { return m_name.Get() ? *m_name.Get() : ""; } - AZStd::string GetTooltip() const { return m_tooltip.Get() ? *m_tooltip.Get() : ""; } - const AZ::Uuid GetReturnType() const { return m_returnType.Get() ? *m_returnType.Get() : AZ::Uuid::CreateNull(); } - const AZStd::vector& GetParameters() const { return m_parameters; } + const AZ::Uuid GetReturnType() const + { + return m_returnType.Get() ? *m_returnType.Get() : AZ::Uuid::CreateNull(); + } - ScriptEventData::VersionedProperty& GetNameProperty() { return m_name; } - ScriptEventData::VersionedProperty& GetTooltipProperty() { return m_tooltip; } - ScriptEventData::VersionedProperty& GetReturnTypeProperty() { return m_returnType; } + const AZStd::vector& GetParameters() const + { + return m_parameters; + } - const ScriptEventData::VersionedProperty& GetNameProperty() const { return m_name; } - const ScriptEventData::VersionedProperty& GetTooltipProperty() const { return m_tooltip; } - const ScriptEventData::VersionedProperty& GetReturnTypeProperty() const { return m_returnType; } + ScriptEventData::VersionedProperty& GetNameProperty() + { + return m_name; + } - AZ::Crc32 GetEventId() const { return AZ::Crc32(GetNameProperty().GetId().ToString().c_str()); } + ScriptEventData::VersionedProperty& GetTooltipProperty() + { + return m_tooltip; + } + ScriptEventData::VersionedProperty& GetReturnTypeProperty() + { + return m_returnType; + } + + const ScriptEventData::VersionedProperty& GetNameProperty() const + { + return m_name; + } + + const ScriptEventData::VersionedProperty& GetTooltipProperty() const + { + return m_tooltip; + } + + const ScriptEventData::VersionedProperty& GetReturnTypeProperty() const + { + return m_returnType; + } + + AZ::Crc32 GetEventId() const + { + return AZ::Crc32(GetNameProperty().GetId().ToString().c_str()); + } //! Validates that the asset data being stored is valid and supported. - AZ::Outcome Validate() const - { - const AZStd::string name = GetName(); - const AZ::Uuid returnType = GetReturnType(); - - // Validate address type - if (!Types::IsValidReturnType(returnType)) - { - return AZ::Failure(AZStd::string::format("The specified type %s is not valid as return type for Script Event: %s", returnType.ToString().c_str(), name.c_str())); - } - - // Definition name cannot be empty - if (name.empty()) - { - return AZ::Failure(AZStd::string("Definition name cannot be empty")); - } - - // Name cannot start with a number - if (isdigit(name.at(0))) - { - return AZ::Failure(AZStd::string::format("%s, names cannot start with a number", name.c_str())); - } - - // Conform to valid function names - AZStd::smatch match; - - // Ascii-only - AZStd::regex asciionly_regex("[^\x0A\x0D\x20-\x7E]"); - AZStd::regex_match(name, match, asciionly_regex); - if (!match.empty()) - { - return AZ::Failure(AZStd::string::format("%s, invalid name, names may only contain ASCII characters", name.c_str())); - } - - AZStd::regex validate_regex("[_[:alpha:]][_[:alnum:]]*"); - AZStd::regex_match(name, match, validate_regex); - if (match.empty()) - { - return AZ::Failure(AZStd::string::format("%s, invalid name specified", name.c_str())); - } - - AZStd::string parameterName; - int parameterIndex = 0; - for (const Parameter& parameter : m_parameters) - { - auto outcome = parameter.Validate(); - if (!outcome.IsSuccess()) - { - return outcome; - } - - if (parameter.GetName().compare(parameterName) == 0) - { - return AZ::Failure(AZStd::string::format("Cannot have duplicate parameter names (%d: %s) make sure each parameter name is unique", parameterIndex, parameterName.c_str())); - } - - parameterName = parameter.GetName(); - ++parameterIndex; - } - - return AZ::Success(true); - } - - void PreSave() - { - m_name.PreSave(); - m_tooltip.PreSave(); - m_returnType.PreSave(); - - for (Parameter parameter : m_parameters) - { - parameter.PreSave(); - } - } - - void Flatten() - { - m_name.Flatten(); - m_tooltip.Flatten(); - m_returnType.Flatten(); - for (Parameter& parameter : m_parameters) - { - parameter.Flatten(); - } - } + AZ::Outcome Validate() const; + void PreSave(); + void Flatten(); private: - ScriptEventData::VersionedProperty m_name; ScriptEventData::VersionedProperty m_tooltip; ScriptEventData::VersionedProperty m_returnType; AZStd::vector m_parameters; + }; - }; - -} +} // namespace ScriptEvents diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventParameter.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventParameter.h index 3871a04be5..ad5b872d79 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventParameter.h +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventParameter.h @@ -9,10 +9,7 @@ #pragma once #include -#include #include -#include -#include namespace ScriptEvents { @@ -45,109 +42,11 @@ namespace ScriptEvents FromScript(dc); } - void FromScript(AZ::ScriptDataContext& dc) - { - if (dc.GetNumArguments() > 0) - { - AZStd::string name; - if (dc.ReadArg(0, name)) - { - m_name.Set(name.c_str()); - } + void FromScript(AZ::ScriptDataContext& dc); - if (dc.GetNumArguments() > 1) - { - AZ::Uuid parameterType; - if (dc.ReadArg(1, parameterType)) - { - m_type.Set(parameterType); - } - } - } - - //AZ_TracePrintf("Script Events", "Added Parameter: %s (type: %s)\n", GetName().c_str(), GetType().ToString() .c_str()); - - } - - static void Reflect(AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Field("m_name", &Parameter::m_name) - ->Field("m_tooltip", &Parameter::m_tooltip) - ->Field("m_type", &Parameter::m_type) - ; - - if (AZ::EditContext* editContext = serializeContext->GetEditContext()) - { - editContext->Class("A Script Event's method parameter", "A parameter to a Script Event's event definition") - ->DataElement(AZ::Edit::UIHandlers::Default, &Parameter::m_name, "Name", "Name of the parameter, ex. void foo(int thisIsTheParameterName)") - ->DataElement(AZ::Edit::UIHandlers::Default, &Parameter::m_tooltip, "Tooltip", "A description of this parameter") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &Parameter::m_type, "Type", "The typeid of the parameter, ex. void foo(AZ::type_info::Uuid())") - ->Attribute(AZ::Edit::Attributes::GenericValueList, &Types::GetValidParameterTypes) - ; - } - } - - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) - { - behaviorContext->Class("Parameter") - ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) - ->Property("Name", BehaviorValueProperty(&Parameter::m_name)) - ->Property("Type", BehaviorValueProperty(&Parameter::m_type)) - ; - } - } - - AZ::Outcome Validate() const - { - const AZStd::string& name = GetName(); - const AZ::Uuid* parameterType = m_type.Get(); - - AZ_Assert(parameterType && !parameterType->IsNull(), "The Parameter type should not be null"); - - // Validate address type - if (!Types::IsValidParameterType(*parameterType)) - { - return AZ::Failure(AZStd::string::format("The specified type %s is not valid as parameter type for Script Event: %s", (*parameterType).ToString().c_str(), name.c_str())); - } - - // Definition name cannot be empty - if (name.empty()) - { - return AZ::Failure(AZStd::string("Definition name cannot be empty")); - } - - // Name cannot start with a number - if (isdigit(name.at(0))) - { - return AZ::Failure(AZStd::string::format("%s, names cannot start with a number", name.c_str())); - } - - // Conform to valid function names - AZStd::smatch match; - - // Ascii-only - AZStd::regex asciionly_regex("[^\x0A\x0D\x20-\x7E]"); - AZStd::regex_match(name, match, asciionly_regex); - if (match.size() > 0) - { - return AZ::Failure(AZStd::string::format("%s, invalid name, names may only contain ASCII characters", name.c_str())); - } - - // Function name syntax - AZStd::regex validate_regex("[_[:alpha:]][_[:alnum:]]*"); - AZStd::regex_match(name, match, validate_regex); - if (match.size() == 0) - { - return AZ::Failure(AZStd::string::format("%s, invalid name specified", name.c_str())); - } - - return AZ::Success(true); - - } + static void Reflect(AZ::ReflectContext* context); + AZ::Outcome Validate() const; AZStd::string GetName() const { return m_name.Get() ? *m_name.Get() : ""; } AZStd::string GetTooltip() const { return m_tooltip.Get() ? *m_tooltip.Get() : ""; } AZ::Uuid GetType() const { return m_type.Get() ? *m_type.Get() : AZ::Uuid::CreateNull(); } diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventTypes.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventTypes.h index a523d932ea..96233e5867 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventTypes.h +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventTypes.h @@ -10,6 +10,14 @@ #include +#include + +namespace AZ +{ + class BehaviorClass; + class BehaviorMethod; +} + namespace ScriptEvents { namespace Types diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsAssetRef.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsAssetRef.h index 619dd42483..526a36f6b9 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsAssetRef.h +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsAssetRef.h @@ -9,12 +9,10 @@ #include #include -#include #include #include #include #include -#include #include @@ -38,40 +36,7 @@ namespace ScriptEvents using AssetChangedCB = AZStd::function&, void* userData)>; - static void Reflect(AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Version(0) - ->Field("Asset", &ScriptEventsAssetRef::m_asset) - ; - - if (AZ::EditContext* editContext = serializeContext->GetEditContext()) - { - editContext->Class("Script Event Asset", "") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->DataElement(AZ::Edit::UIHandlers::Default, &ScriptEventsAssetRef::m_asset, "Script Event Asset", "") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &ScriptEventsAssetRef::OnAssetChanged) - //TODO #lsempe: hook up to open Asset Editor when ready - //->Attribute("EditButton", "") - //->Attribute("EditDescription", "Open in Script Canvas Editor") - //->Attribute("EditCallback", &ScriptEventsAssetRef::LaunchScriptCanvasEditor) - ; - } - } - - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) - { - behaviorContext->Class() - ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) - ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) - ->Attribute(AZ::Script::Attributes::ConstructibleFromNil, false) - ->Method("Get", &ScriptEventsAssetRef::GetDefinition) - ; - } - } + static void Reflect(AZ::ReflectContext* context); ScriptEventsAssetRef() = default; @@ -100,98 +65,22 @@ namespace ScriptEvents return nullptr; } - void SetAsset(const AZ::Data::Asset& asset) - { - m_asset = asset; - - if (m_asset.IsReady()) - { - if (ScriptEventsAsset* scriptEventAsset = m_asset.GetAs()) - { - scriptEventAsset->m_definition.RegisterInternal(); - } - } - else - { - if (AZ::Data::AssetBus::Handler::BusIsConnectedId(m_asset.GetId())) - { - AZ::Data::AssetBus::Handler::BusDisconnect(m_asset.GetId()); - } - - AZ::Data::AssetBus::Handler::BusConnect(m_asset.GetId()); - } - } + void SetAsset(const AZ::Data::Asset& asset); AZ::Data::Asset GetAsset() const { return m_asset; } - void Load(bool loadBlocking /*= false*/) - { - if (!m_asset.IsReady()) - { - AZ::Data::AssetInfo assetInfo; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, m_asset.GetId()); - if (assetInfo.m_assetId.IsValid()) - { - auto& assetManager = AZ::Data::AssetManager::Instance(); - m_asset = assetManager.GetAsset(m_asset.GetId(), azrtti_typeid(), m_asset.GetAutoLoadBehavior()); - - if(loadBlocking) - { - m_asset.BlockUntilLoadComplete(); - } - } - } - } - - AZ::u32 OnAssetChanged() - { - SetAsset(m_asset); - Load(false); - - if (m_assetNotifyCallback) - { - m_assetNotifyCallback(m_asset, m_userData); - } - - return AZ::Edit::PropertyRefreshLevels::None; - } + void Load(bool loadBlocking /*= false*/); + AZ::u32 OnAssetChanged(); //===================================================================== // AZ::Data::AssetBus - void OnAssetReady(AZ::Data::Asset asset) override - { - if (ScriptEventsAsset* scriptEventAsset = m_asset.GetAs()) - { - scriptEventAsset->m_definition.RegisterInternal(); - } - } - - void OnAssetReloaded(AZ::Data::Asset asset) override - { - SetAsset(asset); - - if (m_assetNotifyCallback) - { - m_assetNotifyCallback(m_asset, m_userData); - } - } - - void OnAssetUnloaded([[maybe_unused]] const AZ::Data::AssetId assetId, [[maybe_unused]] const AZ::Data::AssetType assetType) override - { - if (ScriptEventsAsset* ebusAsset = m_asset.GetAs()) - { - bool isRegistered = false; - //ScriptEventsLegacy::RegistrationRequestBus::BroadcastResult(isRegistered, &ScriptEventsLegacy::RegistrationRequestBus::Events::IsBusRegistered, ebusAsset->m_scriptEventsDefinition.m_name); - if (isRegistered) - { - //ScriptEventsLegacy::RegistrationRequestBus::Broadcast(&ScriptEventsLegacy::RegistrationRequestBus::Events::Unregister, ebusAsset->m_scriptEventsDefinition.m_name); - } - } - } + void OnAssetReady(AZ::Data::Asset asset) override; + void OnAssetReloaded(AZ::Data::Asset asset) override; + void OnAssetUnloaded(const AZ::Data::AssetId assetId, const AZ::Data::AssetType assetType) override; void OnAssetSaved(AZ::Data::Asset asset, [[maybe_unused]] bool isSuccessful) override { diff --git a/Gems/ScriptEvents/Code/Source/Editor/ScriptEventsEditorGem.cpp b/Gems/ScriptEvents/Code/Source/Editor/ScriptEventsEditorGem.cpp index 8ac100c01f..8ab014ec15 100644 --- a/Gems/ScriptEvents/Code/Source/Editor/ScriptEventsEditorGem.cpp +++ b/Gems/ScriptEvents/Code/Source/Editor/ScriptEventsEditorGem.cpp @@ -13,6 +13,7 @@ #include #include +#include #if defined(SCRIPTEVENTS_EDITOR) namespace ScriptEvents diff --git a/Gems/ScriptEvents/Code/Source/ScriptEventMethod.cpp b/Gems/ScriptEvents/Code/Source/ScriptEventMethod.cpp new file mode 100644 index 0000000000..5b7bb590af --- /dev/null +++ b/Gems/ScriptEvents/Code/Source/ScriptEventMethod.cpp @@ -0,0 +1,167 @@ +/* + * 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 "ScriptEvents/ScriptEventMethod.h" + +#include +#include +#include + +namespace ScriptEvents +{ + void Method::FromScript(AZ::ScriptDataContext& dc) + { + if (dc.GetNumArguments() > 0) + { + AZStd::string name; + if (dc.IsString(0) && dc.ReadArg(0, name)) + { + m_name.Set(name.c_str()); + } + + if (dc.GetNumArguments() > 1) + { + AZ::Uuid returnType; + if (dc.ReadArg(1, returnType)) + { + m_returnType.Set(returnType); + } + } + } + + // AZ_TracePrintf("Script Events", "Added Script Method: %s (return type: %s)\n", GetName().c_str(), m_returnType.IsEmpty() ? "none" + // : GetReturnType().ToString().c_str()); + } + void Method::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Field("m_name", &Method::m_name) + ->Field("m_tooltip", &Method::m_tooltip) + ->Field("m_returnType", &Method::m_returnType) + ->Field("m_parameters", &Method::m_parameters); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("Script Event", "A script event's definition") + ->DataElement( + AZ::Edit::UIHandlers::Default, &Method::m_name, "Name", + "The specified name for this event, represents a callable function (i.e. MyScriptEvent())") + ->DataElement(AZ::Edit::UIHandlers::Default, &Method::m_tooltip, "Tooltip", "A description of this event") + ->DataElement( + AZ::Edit::UIHandlers::ComboBox, &Method::m_returnType, "Return value type", + "the typeid of the return value, ex. AZ::type_info::Uuid foo()") + ->Attribute(AZ::Edit::Attributes::GenericValueList, &Types::GetValidReturnTypes) + ->DataElement( + AZ::Edit::UIHandlers::Default, &Method::m_parameters, "Parameters", + "A list of parameters for the EBus event, ex. void foo(Parameter1, Parameter2)"); + } + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("Method") + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Method("AddParameter", &Method::AddParameter) + ->Property("Name", BehaviorValueProperty(&Method::m_name)) + ->Property("ReturnType", BehaviorValueProperty(&Method::m_returnType)) + ->Property("Parameters", BehaviorValueProperty(&Method::m_parameters)); + } + } + + AZ::Outcome Method::Validate() const + { + const AZStd::string name = GetName(); + const AZ::Uuid returnType = GetReturnType(); + + // Validate address type + if (!Types::IsValidReturnType(returnType)) + { + return AZ::Failure(AZStd::string::format( + "The specified type %s is not valid as return type for Script Event: %s", returnType.ToString().c_str(), + name.c_str())); + } + + // Definition name cannot be empty + if (name.empty()) + { + return AZ::Failure(AZStd::string("Definition name cannot be empty")); + } + + // Name cannot start with a number + if (isdigit(name.at(0))) + { + return AZ::Failure(AZStd::string::format("%s, names cannot start with a number", name.c_str())); + } + + // Conform to valid function names + AZStd::smatch match; + + // Ascii-only + AZStd::regex asciionly_regex("[^\x0A\x0D\x20-\x7E]"); + AZStd::regex_match(name, match, asciionly_regex); + if (!match.empty()) + { + return AZ::Failure(AZStd::string::format("%s, invalid name, names may only contain ASCII characters", name.c_str())); + } + + AZStd::regex validate_regex("[_[:alpha:]][_[:alnum:]]*"); + AZStd::regex_match(name, match, validate_regex); + if (match.empty()) + { + return AZ::Failure(AZStd::string::format("%s, invalid name specified", name.c_str())); + } + + AZStd::string parameterName; + int parameterIndex = 0; + for (const Parameter& parameter : m_parameters) + { + auto outcome = parameter.Validate(); + if (!outcome.IsSuccess()) + { + return outcome; + } + + if (parameter.GetName().compare(parameterName) == 0) + { + return AZ::Failure(AZStd::string::format( + "Cannot have duplicate parameter names (%d: %s) make sure each parameter name is unique", parameterIndex, + parameterName.c_str())); + } + + parameterName = parameter.GetName(); + ++parameterIndex; + } + + return AZ::Success(true); + } + + void Method::PreSave() + { + m_name.PreSave(); + m_tooltip.PreSave(); + m_returnType.PreSave(); + + for (Parameter parameter : m_parameters) + { + parameter.PreSave(); + } + } + + void Method::Flatten() + { + m_name.Flatten(); + m_tooltip.Flatten(); + m_returnType.Flatten(); + for (Parameter& parameter : m_parameters) + { + parameter.Flatten(); + } + } +} // namespace ScriptEvents diff --git a/Gems/ScriptEvents/Code/Source/ScriptEventParameter.cpp b/Gems/ScriptEvents/Code/Source/ScriptEventParameter.cpp new file mode 100644 index 0000000000..1f888de10f --- /dev/null +++ b/Gems/ScriptEvents/Code/Source/ScriptEventParameter.cpp @@ -0,0 +1,122 @@ +/* + * 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 "ScriptEvents/ScriptEventParameter.h" + +#include +#include +#include +#include + +namespace ScriptEvents +{ + void Parameter::FromScript(AZ::ScriptDataContext& dc) + { + if (dc.GetNumArguments() > 0) + { + AZStd::string name; + if (dc.ReadArg(0, name)) + { + m_name.Set(name.c_str()); + } + + if (dc.GetNumArguments() > 1) + { + AZ::Uuid parameterType; + if (dc.ReadArg(1, parameterType)) + { + m_type.Set(parameterType); + } + } + } + + // AZ_TracePrintf("Script Events", "Added Parameter: %s (type: %s)\n", GetName().c_str(), GetType().ToString() + // .c_str()); + } + + void Parameter::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Field("m_name", &Parameter::m_name) + ->Field("m_tooltip", &Parameter::m_tooltip) + ->Field("m_type", &Parameter::m_type); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("A Script Event's method parameter", "A parameter to a Script Event's event definition") + ->DataElement( + AZ::Edit::UIHandlers::Default, &Parameter::m_name, "Name", + "Name of the parameter, ex. void foo(int thisIsTheParameterName)") + ->DataElement(AZ::Edit::UIHandlers::Default, &Parameter::m_tooltip, "Tooltip", "A description of this parameter") + ->DataElement( + AZ::Edit::UIHandlers::ComboBox, &Parameter::m_type, "Type", + "The typeid of the parameter, ex. void foo(AZ::type_info::Uuid())") + ->Attribute(AZ::Edit::Attributes::GenericValueList, &Types::GetValidParameterTypes); + } + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("Parameter") + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Property("Name", BehaviorValueProperty(&Parameter::m_name)) + ->Property("Type", BehaviorValueProperty(&Parameter::m_type)); + } + } + + AZ::Outcome Parameter::Validate() const + { + const AZStd::string& name = GetName(); + const AZ::Uuid* parameterType = m_type.Get(); + + AZ_Assert(parameterType && !parameterType->IsNull(), "The Parameter type should not be null"); + + // Validate address type + if (!Types::IsValidParameterType(*parameterType)) + { + return AZ::Failure(AZStd::string::format( + "The specified type %s is not valid as parameter type for Script Event: %s", + (*parameterType).ToString().c_str(), name.c_str())); + } + + // Definition name cannot be empty + if (name.empty()) + { + return AZ::Failure(AZStd::string("Definition name cannot be empty")); + } + + // Name cannot start with a number + if (isdigit(name.at(0))) + { + return AZ::Failure(AZStd::string::format("%s, names cannot start with a number", name.c_str())); + } + + // Conform to valid function names + AZStd::smatch match; + + // Ascii-only + AZStd::regex asciionly_regex("[^\x0A\x0D\x20-\x7E]"); + AZStd::regex_match(name, match, asciionly_regex); + if (match.size() > 0) + { + return AZ::Failure(AZStd::string::format("%s, invalid name, names may only contain ASCII characters", name.c_str())); + } + + // Function name syntax + AZStd::regex validate_regex("[_[:alpha:]][_[:alnum:]]*"); + AZStd::regex_match(name, match, validate_regex); + if (match.size() == 0) + { + return AZ::Failure(AZStd::string::format("%s, invalid name specified", name.c_str())); + } + + return AZ::Success(true); + } +} // namespace ScriptEvents diff --git a/Gems/ScriptEvents/Code/Source/ScriptEventsAssetRef.cpp b/Gems/ScriptEvents/Code/Source/ScriptEventsAssetRef.cpp new file mode 100644 index 0000000000..d0aa4e1b10 --- /dev/null +++ b/Gems/ScriptEvents/Code/Source/ScriptEventsAssetRef.cpp @@ -0,0 +1,135 @@ +/* + * 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 "ScriptEvents/ScriptEventsAssetRef.h" + +#include +#include +#include + +namespace ScriptEvents +{ + void ScriptEventsAssetRef::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class()->Version(0)->Field("Asset", &ScriptEventsAssetRef::m_asset); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("Script Event Asset", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->DataElement(AZ::Edit::UIHandlers::Default, &ScriptEventsAssetRef::m_asset, "Script Event Asset", "") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &ScriptEventsAssetRef::OnAssetChanged) + // TODO #lsempe: hook up to open Asset Editor when ready + //->Attribute("EditButton", "") + //->Attribute("EditDescription", "Open in Script Canvas Editor") + //->Attribute("EditCallback", &ScriptEventsAssetRef::LaunchScriptCanvasEditor) + ; + } + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Attribute(AZ::Script::Attributes::ConstructibleFromNil, false) + ->Method("Get", &ScriptEventsAssetRef::GetDefinition); + } + } + + void ScriptEventsAssetRef::SetAsset(const AZ::Data::Asset& asset) + { + m_asset = asset; + + if (m_asset.IsReady()) + { + if (ScriptEventsAsset* scriptEventAsset = m_asset.GetAs()) + { + scriptEventAsset->m_definition.RegisterInternal(); + } + } + else + { + if (AZ::Data::AssetBus::Handler::BusIsConnectedId(m_asset.GetId())) + { + AZ::Data::AssetBus::Handler::BusDisconnect(m_asset.GetId()); + } + + AZ::Data::AssetBus::Handler::BusConnect(m_asset.GetId()); + } + } + + void ScriptEventsAssetRef::Load(bool loadBlocking /*= false*/) + { + if (!m_asset.IsReady()) + { + AZ::Data::AssetInfo assetInfo; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, m_asset.GetId()); + if (assetInfo.m_assetId.IsValid()) + { + auto& assetManager = AZ::Data::AssetManager::Instance(); + m_asset = assetManager.GetAsset(m_asset.GetId(), azrtti_typeid(), m_asset.GetAutoLoadBehavior()); + + if(loadBlocking) + { + m_asset.BlockUntilLoadComplete(); + } + } + } + } + + AZ::u32 ScriptEventsAssetRef::OnAssetChanged() + { + SetAsset(m_asset); + Load(false); + + if (m_assetNotifyCallback) + { + m_assetNotifyCallback(m_asset, m_userData); + } + + return AZ::Edit::PropertyRefreshLevels::None; + } + + void ScriptEventsAssetRef::OnAssetReady(AZ::Data::Asset asset) + { + if (ScriptEventsAsset* scriptEventAsset = m_asset.GetAs()) + { + scriptEventAsset->m_definition.RegisterInternal(); + } + } + + void ScriptEventsAssetRef::OnAssetReloaded(AZ::Data::Asset asset) + { + SetAsset(asset); + + if (m_assetNotifyCallback) + { + m_assetNotifyCallback(m_asset, m_userData); + } + } + + void ScriptEventsAssetRef::OnAssetUnloaded( + [[maybe_unused]] const AZ::Data::AssetId assetId, [[maybe_unused]] const AZ::Data::AssetType assetType) + { + if (ScriptEventsAsset* ebusAsset = m_asset.GetAs()) + { + bool isRegistered = false; + // ScriptEventsLegacy::RegistrationRequestBus::BroadcastResult(isRegistered, + // &ScriptEventsLegacy::RegistrationRequestBus::Events::IsBusRegistered, ebusAsset->m_scriptEventsDefinition.m_name); + if (isRegistered) + { + // ScriptEventsLegacy::RegistrationRequestBus::Broadcast(&ScriptEventsLegacy::RegistrationRequestBus::Events::Unregister, + // ebusAsset->m_scriptEventsDefinition.m_name); + } + } + } +} // namespace ScriptEvents diff --git a/Gems/ScriptEvents/Code/scriptevents_common_files.cmake b/Gems/ScriptEvents/Code/scriptevents_common_files.cmake index c83518db32..5938050f5d 100644 --- a/Gems/ScriptEvents/Code/scriptevents_common_files.cmake +++ b/Gems/ScriptEvents/Code/scriptevents_common_files.cmake @@ -9,6 +9,9 @@ set(FILES Source/ScriptEventsSystemComponent.h Source/ScriptEventsSystemComponent.cpp + Source/ScriptEventParameter.cpp + Source/ScriptEventMethod.cpp + Source/ScriptEventsAssetRef.cpp Include/ScriptEvents/ScriptEventsGem.h Include/ScriptEvents/ScriptEventsAsset.h Include/ScriptEvents/ScriptEventsAsset.cpp diff --git a/Gems/StartingPointInput/Code/Source/InputConfigurationComponent.cpp b/Gems/StartingPointInput/Code/Source/InputConfigurationComponent.cpp index 42fa05473c..215efd4656 100644 --- a/Gems/StartingPointInput/Code/Source/InputConfigurationComponent.cpp +++ b/Gems/StartingPointInput/Code/Source/InputConfigurationComponent.cpp @@ -7,11 +7,12 @@ */ #include "InputConfigurationComponent.h" +#include #include -#include -#include -#include #include +#include +#include +#include #include namespace StartingPointInput diff --git a/Gems/Vegetation/Code/Source/Components/DescriptorListComponent.cpp b/Gems/Vegetation/Code/Source/Components/DescriptorListComponent.cpp index 96bef0abda..de2078e2e5 100644 --- a/Gems/Vegetation/Code/Source/Components/DescriptorListComponent.cpp +++ b/Gems/Vegetation/Code/Source/Components/DescriptorListComponent.cpp @@ -8,6 +8,7 @@ #include "DescriptorListComponent.h" #include +#include #include #include #include diff --git a/Gems/Vegetation/Code/Source/Components/MeshBlockerComponent.cpp b/Gems/Vegetation/Code/Source/Components/MeshBlockerComponent.cpp index dc205079fd..9c7fa34dac 100644 --- a/Gems/Vegetation/Code/Source/Components/MeshBlockerComponent.cpp +++ b/Gems/Vegetation/Code/Source/Components/MeshBlockerComponent.cpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace Vegetation { diff --git a/Gems/Vegetation/Code/Source/DynamicSliceInstanceSpawner.cpp b/Gems/Vegetation/Code/Source/DynamicSliceInstanceSpawner.cpp index 0186bba89d..8e6bbf0ed8 100644 --- a/Gems/Vegetation/Code/Source/DynamicSliceInstanceSpawner.cpp +++ b/Gems/Vegetation/Code/Source/DynamicSliceInstanceSpawner.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/Vegetation/Code/Source/PrefabInstanceSpawner.cpp b/Gems/Vegetation/Code/Source/PrefabInstanceSpawner.cpp index efeb60d598..b386f17cab 100644 --- a/Gems/Vegetation/Code/Source/PrefabInstanceSpawner.cpp +++ b/Gems/Vegetation/Code/Source/PrefabInstanceSpawner.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/Gems/Vegetation/Code/Tests/VegetationMocks.h b/Gems/Vegetation/Code/Tests/VegetationMocks.h index ee620c81a2..ec3760057c 100644 --- a/Gems/Vegetation/Code/Tests/VegetationMocks.h +++ b/Gems/Vegetation/Code/Tests/VegetationMocks.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/WhiteBox/Code/Source/Asset/EditorWhiteBoxMeshAsset.cpp b/Gems/WhiteBox/Code/Source/Asset/EditorWhiteBoxMeshAsset.cpp index 00f5c0e4f4..a02f0e3c6b 100644 --- a/Gems/WhiteBox/Code/Source/Asset/EditorWhiteBoxMeshAsset.cpp +++ b/Gems/WhiteBox/Code/Source/Asset/EditorWhiteBoxMeshAsset.cpp @@ -11,6 +11,7 @@ #include "EditorWhiteBoxMeshAsset.h" #include "Util/WhiteBoxEditorUtil.h" +#include #include #include #include diff --git a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp index f18b69393c..849e2272a2 100644 --- a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp +++ b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp @@ -16,6 +16,7 @@ #include "Util/WhiteBoxEditorUtil.h" #include "WhiteBoxComponent.h" +#include #include #include #include From 02987d90102e361d179c4d20f8d83a0146c758c0 Mon Sep 17 00:00:00 2001 From: nggieber Date: Wed, 29 Sep 2021 09:34:21 -0700 Subject: [PATCH 070/115] Fixed another non-unity build error Signed-off-by: nggieber --- Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp index 9e40a2b231..1839948e80 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include From 94bd95cee3340632bdf637742fe00ae1f1e308eb Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 29 Sep 2021 09:58:04 -0700 Subject: [PATCH 071/115] Solve merge issue Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- Code/Editor/ViewportTitleDlg.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 20b6ac9483..75d16e9a40 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -39,11 +39,8 @@ #include #include -<<<<<<< HEAD -#include -======= #include ->>>>>>> a8559c4000297b8c2876b8213d83f1678dbc3d84 +#include #include #include From b79c2f385d52afa5ff146f41a4ca3508bc12cf65 Mon Sep 17 00:00:00 2001 From: Tommy Walton <82672795+amzn-tommy@users.noreply.github.com> Date: Wed, 29 Sep 2021 11:08:05 -0700 Subject: [PATCH 072/115] Adding a temporary Orphan function to the InstanceDatabase (#4297) * Adding a temporary Orphan function to the InstanceDatabase, which will remove an instance from the database so it will not be found using Find or FindOrCreate. The instance will still persist until its use-count drops to 0, at which point it will be deleted. This is to enable the model asset to remove existing buffer/modellod/model instances and replace them with new instances that have the up to date data. Added unit tests for testing. Signed-off-by: amzn-tommy * Fix an incorrect ceil and update ParallelInstance test cases for readability Signed-off-by: amzn-tommy --- .../AtomCore/AtomCore/Instance/InstanceData.h | 3 + .../AtomCore/Instance/InstanceDatabase.h | 30 ++++ .../AtomCore/Tests/InstanceDatabase.cpp | 169 +++++++++++++++--- 3 files changed, 179 insertions(+), 23 deletions(-) diff --git a/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h b/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h index 33fc93c0f5..6b07d12e9c 100644 --- a/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h +++ b/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h @@ -89,6 +89,9 @@ namespace AZ // Tracks the asset type used to create the instance. AssetType m_assetType; + + // Boolean to indicate if the instance has been orphaned from the instance database + bool m_isOrphaned = false; }; /// @cond EXCLUDE_DOCS diff --git a/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h b/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h index ac97af3629..4b4ad572c2 100644 --- a/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h +++ b/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h @@ -203,6 +203,16 @@ namespace AZ //! Calls FindOrCreate using a random InstanceId Data::Instance Create(const Asset& asset, const AZStd::any* param = nullptr); + /** + * Removes the instance data from the database. Does not release it. + * References to existing instances will remain valid, but new calls to Create/FindOrCreate will create a new instance + * This function is temporary, to provide functionality needed for Model hot-reloading, but will be removed + * once the Model class does not need it anymore. + * + * @param id The id of the instance to remove + */ + void TEMPOrphan(const InstanceId& id); + private: InstanceDatabase(const AssetType& assetType); ~InstanceDatabase(); @@ -356,6 +366,20 @@ namespace AZ return FindOrCreate(Data::InstanceId::CreateRandom(), asset, param); } + template + void InstanceDatabase::TEMPOrphan(const InstanceId& id) + { + AZStd::scoped_lock lock(m_databaseMutex); + // Check if the instance is still in the database, in case it was orphaned twice + auto instanceItr = m_database.find(id); + if (instanceItr != m_database.end()) + { + // Mark the instance as orphaned, and remove it from the database + instanceItr->second->m_isOrphaned = true; + m_database.erase(instanceItr); + } + } + template void InstanceDatabase::ReleaseInstance(InstanceData* instance, const InstanceId& instanceId) { @@ -374,6 +398,12 @@ namespace AZ m_database.erase(instance->GetId()); m_instanceHandler.m_deleteFunction(static_cast(instance)); } + else if (instance->m_isOrphaned && instance->m_useCount.compare_exchange_strong(expectedRefCount, -1)) + { + // If the instance was orphaned, it has already been removed from the database, + // but still needs to be deleted when the refcount drops to 0 + m_instanceHandler.m_deleteFunction(static_cast(instance)); + } } template diff --git a/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp b/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp index 5d1edc5a09..6a5c65ac7a 100644 --- a/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp +++ b/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp @@ -181,7 +181,76 @@ namespace UnitTest EXPECT_EQ(instance, instance3); } - void ParallelInstanceCreateHelper(size_t threadCountMax, size_t assetIdCount, size_t durationSeconds) + TEST_F(InstanceDatabaseTest, InstanceOrphan) + { + auto& assetManager = AssetManager::Instance(); + auto& instanceDatabase = InstanceDatabase::Instance(); + + Asset someAsset = assetManager.CreateAsset(s_assetId0, AZ::Data::AssetLoadBehavior::Default); + + Instance orphanedInstance = instanceDatabase.FindOrCreate(s_instanceId0, someAsset); + EXPECT_NE(orphanedInstance, nullptr); + + instanceDatabase.TEMPOrphan(s_instanceId0); + // After orphan, the instance should not be found in the database, but it should still be valid + EXPECT_EQ(instanceDatabase.Find(s_instanceId0), nullptr); + EXPECT_NE(orphanedInstance, nullptr); + + instanceDatabase.TEMPOrphan(s_instanceId0); + // Orphaning twice should be a no-op + EXPECT_EQ(instanceDatabase.Find(s_instanceId0), nullptr); + EXPECT_NE(orphanedInstance, nullptr); + + Instance instance2 = instanceDatabase.FindOrCreate(s_instanceId0, someAsset); + // Creating another instance with the same id should return a different instance than the one that was orphaned + EXPECT_NE(orphanedInstance, instance2); + } + + enum class ParallelInstanceTestCases + { + Create, + CreateAndDeferRemoval, + CreateAndOrphan, + CreateDeferRemovalAndOrphan + }; + + enum class ParralleInstanceCurrentAction + { + Create, + DeferredRemoval, + Orphan + }; + + ParralleInstanceCurrentAction ParallelInstanceGetCurrentAction(ParallelInstanceTestCases testCase) + { + switch (testCase) + { + case ParallelInstanceTestCases::CreateAndDeferRemoval: + switch (rand() % 2) + { + case 0: return ParralleInstanceCurrentAction::Create; + case 1: return ParralleInstanceCurrentAction::DeferredRemoval; + } + case ParallelInstanceTestCases::CreateAndOrphan: + switch (rand() % 2) + { + case 0: return ParralleInstanceCurrentAction::Create; + case 1: return ParralleInstanceCurrentAction::Orphan; + } + case ParallelInstanceTestCases::CreateDeferRemovalAndOrphan: + switch (rand() % 3) + { + case 0: return ParralleInstanceCurrentAction::Create; + case 1: return ParralleInstanceCurrentAction::DeferredRemoval; + case 2: return ParralleInstanceCurrentAction::Orphan; + } + case ParallelInstanceTestCases::Create: + default: + return ParralleInstanceCurrentAction::Create; + } + } + + void ParallelInstanceCreateHelper(size_t threadCountMax, size_t assetIdCount, float durationSeconds, ParallelInstanceTestCases testCase) { printf("Testing threads=%zu assetIds=%zu ... ", threadCountMax, assetIdCount); @@ -192,6 +261,7 @@ namespace UnitTest auto& instanceManager = InstanceDatabase::Instance(); AZStd::vector guids; + AZStd::vector> instances; AZStd::vector> assets; for (size_t i = 0; i < assetIdCount; ++i) @@ -199,6 +269,7 @@ namespace UnitTest Uuid guid = Uuid::CreateRandom(); guids.emplace_back(guid); + instances.emplace_back(nullptr); // Pre-create asset so we don't attempt to load it from the catalog. assets.emplace_back(assetManager.CreateAsset(guid, AZ::Data::AssetLoadBehavior::Default)); @@ -206,6 +277,7 @@ namespace UnitTest AZStd::vector threads; AZStd::mutex mutex; + AZStd::mutex referenceTableMutex; AZStd::atomic threadCount((int)threadCountMax); AZStd::condition_variable cv; AZStd::atomic_bool keepDispatching(true); @@ -225,11 +297,15 @@ namespace UnitTest for (size_t i = 0; i < threadCountMax; ++i) { threads.emplace_back( - [&instanceManager, &threadCount, &cv, &guids, &assets, &durationSeconds]() + [&instanceManager, &threadCount, &cv, &guids, &instances, &assets, &durationSeconds, &testCase, &referenceTableMutex]() { AZ::Debug::Timer timer; timer.Stamp(); + bool deferRemoval = testCase == ParallelInstanceTestCases::CreateAndDeferRemoval || + testCase == ParallelInstanceTestCases::CreateDeferRemovalAndOrphan + ? true : false; + while (timer.GetDeltaTimeInSeconds() < durationSeconds) { const size_t index = rand() % guids.size(); @@ -237,11 +313,36 @@ namespace UnitTest const InstanceId instanceId{ uuid }; const AssetId assetId{ uuid }; - Instance instance = - instanceManager.FindOrCreate(instanceId, Asset(assetId, azrtti_typeid())); - EXPECT_NE(instance, nullptr); - EXPECT_EQ(instance->GetId(), instanceId); - EXPECT_EQ(instance->m_asset, assets[index]); + ParralleInstanceCurrentAction currentAction = ParallelInstanceGetCurrentAction(testCase); + + if (currentAction == ParralleInstanceCurrentAction::Orphan) + { + // Orphan the instance, but don't decrease its refcount + instanceManager.TEMPOrphan(instanceId); + } + else if (currentAction == ParralleInstanceCurrentAction::DeferredRemoval) + { + // Drop the refcount to zero so the instance will be released + referenceTableMutex.lock(); + instances[index] = nullptr; + referenceTableMutex.unlock(); + } + else + { + // Otherwise, add a new instance + Instance instance = instanceManager.FindOrCreate(instanceId, assets[index]); + EXPECT_NE(instance, nullptr); + EXPECT_EQ(instance->GetId(), instanceId); + EXPECT_EQ(instance->m_asset, assets[index]); + + if (deferRemoval) + { + // Keep a reference to the instance alive so it can be removed later + referenceTableMutex.lock(); + instances[index] = instance; + referenceTableMutex.unlock(); + } + } } threadCount--; @@ -254,10 +355,12 @@ namespace UnitTest // Used to detect a deadlock. If we wait for more than 10 seconds, it's likely a deadlock has occurred while (threadCount > 0 && !timedOut) { + size_t durationSecondsRoundedUp = static_cast(std::ceil(durationSeconds)); + AZStd::unique_lock lock(mutex); timedOut = (AZStd::cv_status::timeout == - cv.wait_until(lock, AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(durationSeconds * 2))); + cv.wait_until(lock, AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(durationSecondsRoundedUp * 2))); } EXPECT_TRUE(threadCount == 0) << "One or more threads appear to be deadlocked at " << timer.GetDeltaTimeInSeconds() << " seconds"; @@ -273,11 +376,11 @@ namespace UnitTest printf("Took %f seconds\n", timer.GetDeltaTimeInSeconds()); } - TEST_F(InstanceDatabaseTest, ParallelInstanceCreate) + void ParallelCreateTest(ParallelInstanceTestCases testCase) { // This is the original test scenario from when InstanceDatabase was first implemented // threads, AssetIds, seconds - ParallelInstanceCreateHelper(8, 100, 5); + ParallelInstanceCreateHelper(8, 100, 5, testCase); // This value is checked in as 1 so this test doesn't take too much time, but can be increased locally to soak the test. const size_t attempts = 1; @@ -289,11 +392,11 @@ namespace UnitTest // The idea behind this series of tests is that there are two threads sharing one Instance, and both threads try to // create or release that instance at the same time. // At the time, this set of scenarios has something like a 10% failure rate. - const size_t duration = 2; + const float duration = 2.0f; // threads, AssetIds, seconds - ParallelInstanceCreateHelper(2, 1, duration); - ParallelInstanceCreateHelper(4, 1, duration); - ParallelInstanceCreateHelper(8, 1, duration); + ParallelInstanceCreateHelper(2, 1, duration, testCase); + ParallelInstanceCreateHelper(4, 1, duration, testCase); + ParallelInstanceCreateHelper(8, 1, duration, testCase); } for (size_t i = 0; i < attempts; ++i) @@ -301,19 +404,39 @@ namespace UnitTest printf("Attempt %zu of %zu... \n", i, attempts); // Here we try a bunch of different threadCount:assetCount ratios to be thorough - const size_t duration = 2; + const float duration = 2.0f; // threads, AssetIds, seconds - ParallelInstanceCreateHelper(2, 1, duration); - ParallelInstanceCreateHelper(4, 1, duration); - ParallelInstanceCreateHelper(4, 2, duration); - ParallelInstanceCreateHelper(4, 4, duration); - ParallelInstanceCreateHelper(8, 1, duration); - ParallelInstanceCreateHelper(8, 2, duration); - ParallelInstanceCreateHelper(8, 3, duration); - ParallelInstanceCreateHelper(8, 4, duration); + ParallelInstanceCreateHelper(2, 1, duration, testCase); + ParallelInstanceCreateHelper(4, 1, duration, testCase); + ParallelInstanceCreateHelper(4, 2, duration, testCase); + ParallelInstanceCreateHelper(4, 4, duration, testCase); + ParallelInstanceCreateHelper(8, 1, duration, testCase); + ParallelInstanceCreateHelper(8, 2, duration, testCase); + ParallelInstanceCreateHelper(8, 3, duration, testCase); + ParallelInstanceCreateHelper(8, 4, duration, testCase); } } + TEST_F(InstanceDatabaseTest, ParallelInstanceCreate) + { + ParallelCreateTest(ParallelInstanceTestCases::Create); + } + + TEST_F(InstanceDatabaseTest, ParallelInstanceCreateAndDeferRemoval) + { + ParallelCreateTest(ParallelInstanceTestCases::CreateAndDeferRemoval); + } + + TEST_F(InstanceDatabaseTest, ParallelInstanceCreateAndOrphan) + { + ParallelCreateTest(ParallelInstanceTestCases::CreateAndOrphan); + } + + TEST_F(InstanceDatabaseTest, ParallelInstanceCreateDeferRemovalAndOrphan) + { + ParallelCreateTest(ParallelInstanceTestCases::CreateDeferRemovalAndOrphan); + } + TEST_F(InstanceDatabaseTest, InstanceCreateNoDatabase) { bool m_deleted = false; From 96d833fc4e04482897f4185013ff68da8332b976 Mon Sep 17 00:00:00 2001 From: amzn-tommy Date: Wed, 29 Sep 2021 12:07:01 -0700 Subject: [PATCH 073/115] Removing a function that was originally added to convert model asset ids in levels that were created prior to December 2020, which pre-dates anything created for the public O3DE release. Signed-off-by: amzn-tommy --- .../Source/Mesh/MeshComponentController.cpp | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 2dc3b9134a..6cdb44a9e1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -194,41 +194,13 @@ namespace AZ incompatible.push_back(AZ_CRC("MeshService", 0x71d8a455)); } - // [GFX TODO] [ATOM-13339] Remove the ModelAsset id fix up function in MeshComponentController - // Model id was changed due to fix for [ATOM-13312]. We can remove this code when all the levels are updated. - void FixUpModelAsset(Data::Asset& modelAsset) - { - Data::AssetId assetId; - Data::AssetCatalogRequestBus::BroadcastResult( - assetId, - &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - modelAsset.GetHint().c_str(), - AZ::RPI::ModelAsset::TYPEINFO_Uuid(), - false); - if (assetId != modelAsset.GetId()) - { - if (assetId.IsValid()) - { - modelAsset = Data::Asset{ assetId, AZ::RPI::ModelAsset::TYPEINFO_Uuid(), modelAsset.GetHint().c_str() }; - modelAsset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::QueueLoad); - } - else - { - AZ_Error("MeshComponentController", false, "Failed to find asset id for [%s] ", modelAsset.GetHint().c_str()); - } - } - } - MeshComponentController::MeshComponentController(const MeshComponentConfig& config) : m_configuration(config) { - FixUpModelAsset(m_configuration.m_modelAsset); } void MeshComponentController::Activate(const AZ::EntityComponentIdPair& entityComponentIdPair) { - FixUpModelAsset(m_configuration.m_modelAsset); - const AZ::EntityId entityId = entityComponentIdPair.GetEntityId(); m_entityComponentIdPair = entityComponentIdPair; From a7f6bfbb507137c2ca761b132ba0db4990751514 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 29 Sep 2021 14:21:19 -0700 Subject: [PATCH 074/115] Fix tests to work with new interface APIs using EditorEntityContextId Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Tests/FocusMode/EditorFocusModeTests.cpp | 20 +++++++++++----- .../Prefab/PrefabFocus/PrefabFocusTests.cpp | 24 +++++++++++-------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp index 5972da58a7..59fcf85662 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp @@ -75,11 +75,15 @@ namespace AzToolsFramework FocusModeInterface* focusModeInterface = AZ::Interface::Get(); EXPECT_TRUE(focusModeInterface != nullptr); - focusModeInterface->SetFocusRoot(m_entityMap["carId"]); - EXPECT_EQ(focusModeInterface->GetFocusRoot(), m_entityMap["carId"]); + AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( + editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); - focusModeInterface->ClearFocusRoot(); - EXPECT_EQ(focusModeInterface->GetFocusRoot(), AZ::EntityId()); + focusModeInterface->SetFocusRoot(m_entityMap["carId"]); + EXPECT_EQ(focusModeInterface->GetFocusRoot(editorEntityContextId), m_entityMap["carId"]); + + focusModeInterface->ClearFocusRoot(editorEntityContextId); + EXPECT_EQ(focusModeInterface->GetFocusRoot(editorEntityContextId), AZ::EntityId()); } TEST_F(EditorFocusModeTests, EditorFocusModeTests_IsInFocusSubTree) @@ -87,7 +91,11 @@ namespace AzToolsFramework FocusModeInterface* focusModeInterface = AZ::Interface::Get(); EXPECT_TRUE(focusModeInterface != nullptr); - focusModeInterface->ClearFocusRoot(); + AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( + editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); + + focusModeInterface->ClearFocusRoot(editorEntityContextId); EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), true); EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true); @@ -123,6 +131,6 @@ namespace AzToolsFramework EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false); EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true); - focusModeInterface->ClearFocusRoot(); + focusModeInterface->ClearFocusRoot(editorEntityContextId); } } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp index ffd6cd2a44..92de47fa62 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp @@ -69,15 +69,19 @@ namespace UnitTest { GenerateTestHierarchy(); + AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( + editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); + PrefabFocusInterface* prefabFocusInterface = AZ::Interface::Get(); EXPECT_TRUE(prefabFocusInterface != nullptr); // Verify FocusOnOwningPrefab works when passing the container entity of the root prefab. { prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId()); + EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(editorEntityContextId), m_instanceMap["city"]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = prefabFocusInterface->GetFocusedPrefabInstance(editorEntityContextId); EXPECT_TRUE(instance.has_value()); EXPECT_EQ(&instance->get(), m_instanceMap["city"]); } @@ -85,9 +89,9 @@ namespace UnitTest // Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab. { prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["city"]->GetId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId()); + EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(editorEntityContextId), m_instanceMap["city"]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = prefabFocusInterface->GetFocusedPrefabInstance(editorEntityContextId); EXPECT_TRUE(instance.has_value()); EXPECT_EQ(&instance->get(), m_instanceMap["city"]); } @@ -95,9 +99,9 @@ namespace UnitTest // Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab. { prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["car"]->GetContainerEntityId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId()); + EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(editorEntityContextId), m_instanceMap["car"]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = prefabFocusInterface->GetFocusedPrefabInstance(editorEntityContextId); EXPECT_TRUE(instance.has_value()); EXPECT_EQ(&instance->get(), m_instanceMap["car"]); } @@ -105,9 +109,9 @@ namespace UnitTest // Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab. { prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["passenger1"]->GetId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId()); + EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(editorEntityContextId), m_instanceMap["car"]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = prefabFocusInterface->GetFocusedPrefabInstance(editorEntityContextId); EXPECT_TRUE(instance.has_value()); EXPECT_EQ(&instance->get(), m_instanceMap["car"]); } @@ -121,9 +125,9 @@ namespace UnitTest EXPECT_TRUE(rootPrefabInstance.has_value()); prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), rootPrefabInstance->get().GetTemplateId()); + EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(editorEntityContextId), rootPrefabInstance->get().GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = prefabFocusInterface->GetFocusedPrefabInstance(editorEntityContextId); EXPECT_TRUE(instance.has_value()); EXPECT_EQ(&instance->get(), &rootPrefabInstance->get()); } From c9ea34d45fbdea80778b58ea8b64ac150ab89554 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Wed, 29 Sep 2021 14:58:22 -0700 Subject: [PATCH 075/115] Quick updates to AzNetworking unit tests Signed-off-by: puvvadar --- .../DataStructures/FixedSizeBitsetView.inl | 6 ++--- .../DataStructures/FixedSizeBitsetTests.cpp | 3 +++ .../FixedSizeBitsetViewTests.cpp | 23 +++++++++++++++++++ .../Tests/TcpTransport/TcpTransportTests.cpp | 5 ++++ .../Tests/UdpTransport/UdpTransportTests.cpp | 21 +++++++++++++++++ .../Tests/Utilities/IpAddressTests.cpp | 12 ++++++++++ .../Tests/Utilities/QuantizedValuesTests.cpp | 5 ++-- 7 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitsetView.inl b/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitsetView.inl index 8cbdd27e09..6192cfa878 100644 --- a/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitsetView.inl +++ b/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitsetView.inl @@ -15,12 +15,12 @@ namespace AzNetworking , m_startOffset(startOffset) , m_count(startOffset < bitset.GetValidBitCount() && startOffset + count <= bitset.GetValidBitCount() ? count : 0) { - AZ_Assert(startOffset + count <= bitset.GetValidBitCount(), "Out of bounds setup in BitsetSubset. Defaulting to 0 bit count."); + AZ_Warning("FixedSizeBitsetView", startOffset + count <= bitset.GetValidBitCount(), "Out of bounds setup in BitsetSubset. Defaulting to 0 bit count."); } inline void FixedSizeBitsetView::SetBit(uint32_t index, bool value) { - AZ_Assert(index < m_count, "Out of bounds access in BitsetSubset (requested %u, count %u)", index, m_count); + AZ_Warning("FixedSizeBitsetView", index < m_count, "Out of bounds access in BitsetSubset (requested %u, count %u)", index, m_count); if (m_count) { m_bitset.SetBit(m_startOffset + index, value); @@ -29,7 +29,7 @@ namespace AzNetworking inline bool FixedSizeBitsetView::GetBit(uint32_t index) const { - AZ_Assert(index < m_count, "Out of bounds access in BitsetSubset (requested %u, count %u)", index, m_count); + AZ_Warning("FixedSizeBitsetView", index < m_count, "Out of bounds access in BitsetSubset (requested %u, count %u)", index, m_count); if (m_count) { return m_bitset.GetBit(m_startOffset + index); diff --git a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetTests.cpp b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetTests.cpp index f22e815526..12e242c86c 100644 --- a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetTests.cpp +++ b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetTests.cpp @@ -55,5 +55,8 @@ namespace UnitTest unusedBitTest.SetBit(i, false); } EXPECT_FALSE(unusedBitTest.AnySet()); + + unusedBitTest.SetBit(0, true); + EXPECT_TRUE(unusedBitTest.AnySet()); } } diff --git a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp index 6f32eacda9..37547ce5e9 100644 --- a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp +++ b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp @@ -42,4 +42,27 @@ namespace UnitTest EXPECT_FALSE(view.GetBit(0)); } } + + TEST(FixedSizeBitsetView, EmptyBitset) + { + AzNetworking::FixedSizeBitset<32> bitset; + AzNetworking::FixedSizeBitsetView view(bitset, 10, 0); + EXPECT_FALSE(view.GetBit(0)); + } + + TEST(FixedSizeBitsetView, TestAnySet) + { + AzNetworking::FixedSizeBitset<9> unusedBitTest(true); + AzNetworking::FixedSizeBitsetView view(unusedBitTest, 0, 5); + for (uint32_t i = 0; i < 5; ++i) + { + view.SetBit(i, false); + } + EXPECT_FALSE(view.AnySet()); + + view.SetBit(0, true); + EXPECT_TRUE(view.AnySet()); + + EXPECT_EQ(view.GetValidBitCount(), 5); + } } diff --git a/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp b/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp index bc9ecab2cb..3031f66774 100644 --- a/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp +++ b/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp @@ -148,6 +148,11 @@ namespace UnitTest EXPECT_EQ(testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); EXPECT_EQ(testClient.m_clientNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); + + testClient.m_clientNetworkInterface->SetTimeoutEnabled(true); + EXPECT_TRUE(testClient.m_clientNetworkInterface->IsTimeoutEnabled()); + + EXPECT_TRUE(testServer.m_serverNetworkInterface->StopListening()); } #if AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS diff --git a/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp b/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp index c4de3fc6dd..91db3b4549 100644 --- a/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp +++ b/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp @@ -125,6 +125,18 @@ namespace UnitTest AzNetworking::NetworkingSystemComponent* m_networkingSystemComponent; }; + TEST_F(UdpTransportTests, PacketIdWrap) + { + const uint32_t SEQUENCE_BOUNDARY = 0xFFFF; + UdpPacketTracker tracker; + + for (uint32_t i = 0; i < SEQUENCE_BOUNDARY; ++i) + { + tracker.GetNextPacketId(); + } + EXPECT_EQ(tracker.GetNextPacketId(), PacketId(SEQUENCE_BOUNDARY + 1)); + } + TEST_F(UdpTransportTests, AckReplication) { static const SequenceId TestReliableSequenceId = InvalidSequenceId; @@ -266,6 +278,15 @@ namespace UnitTest EXPECT_EQ(testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); EXPECT_EQ(testClient.m_clientNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); + + testClient.m_clientNetworkInterface->SetTimeoutEnabled(true); + EXPECT_TRUE(testClient.m_clientNetworkInterface->IsTimeoutEnabled()); + + EXPECT_FALSE(dynamic_cast(testClient.m_clientNetworkInterface)->IsEncrypted()); + + EXPECT_TRUE(testServer.m_serverNetworkInterface->StopListening()); + EXPECT_FALSE(testServer.m_serverNetworkInterface->StopListening()); + EXPECT_FALSE(dynamic_cast(testServer.m_serverNetworkInterface)->IsOpen()); } TEST_F(UdpTransportTests, TestMultipleClients) diff --git a/Code/Framework/AzNetworking/Tests/Utilities/IpAddressTests.cpp b/Code/Framework/AzNetworking/Tests/Utilities/IpAddressTests.cpp index 435ebb48e0..c143556670 100644 --- a/Code/Framework/AzNetworking/Tests/Utilities/IpAddressTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Utilities/IpAddressTests.cpp @@ -11,4 +11,16 @@ namespace UnitTest { + TEST(IpAddressTests, TestIpQuads) + { + const AzNetworking::IpAddress ip = AzNetworking::IpAddress(127, 0, 0, 1, 12345); + + EXPECT_EQ(ip.GetQuadA(), 127); + EXPECT_EQ(ip.GetQuadB(), 0); + EXPECT_EQ(ip.GetQuadC(), 0); + EXPECT_EQ(ip.GetQuadD(), 1); + + EXPECT_EQ(ip.GetString(), "127.0.0.1:12345"); + EXPECT_EQ(ip.GetIpString(), "127.0.0.1"); + } } diff --git a/Code/Framework/AzNetworking/Tests/Utilities/QuantizedValuesTests.cpp b/Code/Framework/AzNetworking/Tests/Utilities/QuantizedValuesTests.cpp index 13bf9bdb0a..0f0bcac54d 100644 --- a/Code/Framework/AzNetworking/Tests/Utilities/QuantizedValuesTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Utilities/QuantizedValuesTests.cpp @@ -79,13 +79,12 @@ namespace UnitTest template void TestQuantizedValuesHelper01() { - AzNetworking::QuantizedValues testIn, testOut; // Transmits float values between 0 and 1 using NUM_BYTES + AzNetworking::QuantizedValues testIn(ValueFromFloat::Construct(0.0f)), testOut; // Transmits float values between 0 and 1 using NUM_BYTES AZStd::array buffer; AzNetworking::NetworkInputSerializer inputSerializer(buffer.data(), static_cast(buffer.size())); AzNetworking::NetworkOutputSerializer outputSerializer(buffer.data(), static_cast(buffer.size())); - testIn = ValueFromFloat::Construct(0.0f); EXPECT_EQ(static_cast::ValueType>(testIn), ValueFromFloat::Construct(0.0f)); testIn.Serialize(inputSerializer); EXPECT_EQ(inputSerializer.GetSize(), NUM_BYTES * NUM_ELEMENTS); @@ -95,6 +94,8 @@ namespace UnitTest testIn = ValueFromFloat::Construct(1.0f); EXPECT_EQ(static_cast::ValueType>(testIn), ValueFromFloat::Construct(1.0f)); testIn.Serialize(inputSerializer); + EXPECT_NE(testIn, testOut); + EXPECT_NE(testIn.GetQuantizedIntegralValues()[0], testOut.GetQuantizedIntegralValues()[0]); testOut.Serialize(outputSerializer); EXPECT_EQ(testIn, testOut); From 325294aef887f61f1552fd99518bc1170255ca00 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Wed, 29 Sep 2021 15:28:57 -0700 Subject: [PATCH 076/115] Remove magic number in AZN unit Signed-off-by: puvvadar --- .../Tests/DataStructures/FixedSizeBitsetViewTests.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp index 37547ce5e9..8ac3b63f1b 100644 --- a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp +++ b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp @@ -52,9 +52,11 @@ namespace UnitTest TEST(FixedSizeBitsetView, TestAnySet) { + const uint32_t VIEW_SIZE = 5; + AzNetworking::FixedSizeBitset<9> unusedBitTest(true); - AzNetworking::FixedSizeBitsetView view(unusedBitTest, 0, 5); - for (uint32_t i = 0; i < 5; ++i) + AzNetworking::FixedSizeBitsetView view(unusedBitTest, 0, VIEW_SIZE); + for (uint32_t i = 0; i < VIEW_SIZE; ++i) { view.SetBit(i, false); } @@ -63,6 +65,6 @@ namespace UnitTest view.SetBit(0, true); EXPECT_TRUE(view.AnySet()); - EXPECT_EQ(view.GetValidBitCount(), 5); + EXPECT_EQ(view.GetValidBitCount(), VIEW_SIZE); } } From 0f4a9d70b523722d5c7dda2cbf63a9152bc29576 Mon Sep 17 00:00:00 2001 From: jiaweig <51759646+jiaweig-amzn@users.noreply.github.com> Date: Wed, 29 Sep 2021 15:46:35 -0700 Subject: [PATCH 077/115] Fix 3p path setting to the upper level (#4399) Signed-off-by: jiaweig --- cmake/Tools/Platform/Android/generate_android_project.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/Tools/Platform/Android/generate_android_project.py b/cmake/Tools/Platform/Android/generate_android_project.py index a508329d02..d8f1021590 100755 --- a/cmake/Tools/Platform/Android/generate_android_project.py +++ b/cmake/Tools/Platform/Android/generate_android_project.py @@ -368,7 +368,6 @@ def main(args): if not third_party_path.is_dir(): raise common.LmbrCmdError(f"Invalid --third-party-path '{parsed_args.third_party_path}'.", common.ERROR_CODE_INVALID_PARAMETER) - third_party_path = third_party_path.parent build_dir = parsed_args.build_dir From 816a623c97aa9abef13557ba13ac5f7db73e1ad7 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 29 Sep 2021 17:49:02 -0500 Subject: [PATCH 078/115] Added missing EntityId.h include to FocusModeInterface.h (#4396) * Added missing EntityId.h include to FocusModeInterface.h Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Non-unity build fix Adding missing BehaviorContext.h includes to Multiplayer Gem Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added missing BehaviorContext.h include to NetworkCharacterComponent Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzNetworking/Framework/NetworkingSystemComponent.cpp | 1 + .../AzToolsFramework/FocusMode/FocusModeInterface.h | 1 + .../Code/Source/Components/NetworkCharacterComponent.cpp | 9 +++++---- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Framework/NetworkingSystemComponent.cpp b/Code/Framework/AzNetworking/AzNetworking/Framework/NetworkingSystemComponent.cpp index 83588f4acb..16e4e26f67 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Framework/NetworkingSystemComponent.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Framework/NetworkingSystemComponent.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace AzNetworking diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h index a4b90f95b7..a2b23fa8d6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp index 33eb26653a..9e15ae6ce0 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -19,7 +20,7 @@ namespace Multiplayer { - + bool CollisionLayerBasedControllerFilter(const physx::PxController& controllerA, const physx::PxController& controllerB) { PHYSX_SCENE_READ_LOCK(controllerA.getActor()->getScene()); @@ -82,7 +83,7 @@ namespace Multiplayer return physx::PxQueryHitType::eNONE; } - + void NetworkCharacterComponent::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -116,7 +117,7 @@ namespace Multiplayer callbackManager->SetObjectPreFilter(CollisionLayerBasedObjectPreFilter); } } - + if (!HasController()) { GetNetworkTransformComponent()->TranslationAddEvent(m_translationEventHandler); @@ -134,7 +135,7 @@ namespace Multiplayer } void NetworkCharacterComponent::OnSyncRewind() - { + { if (m_physicsCharacter == nullptr) { return; From 090aa8f05339fe7ce2988bc882b818c194c7a34b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 29 Sep 2021 18:13:37 -0500 Subject: [PATCH 079/115] Removed ununeeded includes from EBus EBus.h and Policies.h (#4256) * Removed ununeeded includes from EBus EBus.h and Policies.h Updated the locations which needed those includes Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Adding missing include for to AWsClientAuthBus.h Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Remove the while true loop in the EBusQueuePolicy Execute() function The while true loop in Execute was for allowing additional functions to be queued in the middle of execution of current list of functions. That functionality was dangerous, because if a queued function added itself during execution unconditionally, then it would result in an infinite loop Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AssetManager::DispatchEvents function to pump the AssetBus event queue until empty Queued Events on the AssetBus is able to queue additional events on that Bus during execution of those events. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Changed the AssetManager::DispatchEvents function to only execute the AssetBus queued events once Changed the AssetJobsFloodTest.AssetWithNoLoadReference_LoadDependencies_BehaviorObeyed test to dispatch events until the OnAssetContainerReady callback is signaled. This happens after every asset load to make sure that the expiring AssetContainer instances are removed from `AssetManager::m_ownedAssetContainer` container before retrying to load the same asset. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added a MaxTimeoutSeconds constant for the maximum amount of the time to run a single DispatchEvents loop Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/AzCore/Asset/AssetManager.cpp | 8 ++ .../AzCore/AzCore/Component/Component.h | 1 + .../AzCore/AzCore/Debug/AssetTracking.h | 1 + Code/Framework/AzCore/AzCore/EBus/EBus.h | 17 ++- .../AzCore/AzCore/EBus/IEventScheduler.h | 1 + Code/Framework/AzCore/AzCore/EBus/Policies.h | 37 +++--- .../AzCore/AzCore/RTTI/BehaviorContext.h | 1 + .../Tests/Asset/AssetManagerLoadingTests.cpp | 116 ++++++++++++++---- Code/Framework/AzCore/Tests/UUIDTests.cpp | 1 + .../AzFramework/Archive/ZipDirCache.h | 1 + .../AzFramework/Logging/MissingAssetLogger.h | 1 + .../Render/GeometryIntersectionStructures.h | 1 + .../AzFramework/Windowing/NativeWindow.h | 1 + .../UdpTransport/UdpConnectionSet.h | 1 + .../Entries/AssetBrowserEntryCache.h | 1 + .../Entries/RootAssetBrowserEntry.h | 1 + .../Manipulators/BaseManipulator.h | 2 +- .../SourceControl/SourceControlAPI.h | 1 + .../AzToolsFramework/ViewportUi/ButtonGroup.h | 1 + .../unittests/AssetProcessorServerUnitTests.h | 1 + .../ProjectManager/Source/PythonBindings.cpp | 1 + .../Source/LUA/LUAEditorStyleMessages.h | 1 + .../Code/Include/Private/AWSClientAuthBus.h | 2 + .../Private/Editor/UI/AWSCoreEditorMenu.h | 1 + .../Code/Source/AssetMemoryAnalyzer.cpp | 1 + .../Include/Atom/RHI/ThreadLocalContext.h | 1 + .../Window/MaterialEditorWindowSettings.h | 1 + .../Atom/Utils/AssetCollectionAsyncLoader.h | 1 + .../Utils/StateControllers/StateController.h | 1 + .../EditorAutomation/EditorAutomationTest.h | 1 + 30 files changed, 148 insertions(+), 58 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp index 98182a9568..8eb620f69e 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp @@ -340,6 +340,14 @@ namespace AZ // (Load jobs will attempt to reuse blocked threads before spinning off new job threads) ProcessLoadJob(); } + + // Pump the AssetBus function queue once more after the load has completed in case additional + // functions have been queued between the last call to DispatchEvents and the completion + // of the current load job + if (m_shouldDispatchEvents) + { + AssetManager::Instance().DispatchEvents(); + } } void Finish() diff --git a/Code/Framework/AzCore/AzCore/Component/Component.h b/Code/Framework/AzCore/AzCore/Component/Component.h index 3cbb9b5a86..677517d896 100644 --- a/Code/Framework/AzCore/AzCore/Component/Component.h +++ b/Code/Framework/AzCore/AzCore/Component/Component.h @@ -22,6 +22,7 @@ #include #include // Used as the allocator for most components. #include +#include namespace AZ { diff --git a/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h b/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h index 5c3c835271..615634c05a 100644 --- a/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h +++ b/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include diff --git a/Code/Framework/AzCore/AzCore/EBus/EBus.h b/Code/Framework/AzCore/AzCore/EBus/EBus.h index 58754ff9b8..ff8966e8e0 100644 --- a/Code/Framework/AzCore/AzCore/EBus/EBus.h +++ b/Code/Framework/AzCore/AzCore/EBus/EBus.h @@ -19,14 +19,11 @@ #pragma once #include +#include #include #include - // Included for backwards compatibility purposes -#include -#include #include -// End backwards compat #include #include @@ -90,14 +87,14 @@ namespace AZ * For available settings, see AZ::EBusHandlerPolicy. * By default, an EBus supports any number of handlers. */ - static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Multiple; + static constexpr EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Multiple; /** * Defines how many addresses exist on the EBus. * For available settings, see AZ::EBusAddressPolicy. * By default, an EBus uses a single address. */ - static const EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single; + static constexpr EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single; /** * The type of ID that is used to address the EBus. @@ -152,14 +149,14 @@ namespace AZ * `::ExecuteQueuedEvents()`. * By default, the event queue is disabled. */ - static const bool EnableEventQueue = false; + static constexpr bool EnableEventQueue = false; /** * Specifies whether the bus should accept queued messages by default or not. * If set to false, Bus::AllowFunctionQueuing(true) must be called before events are accepted. * Used only when #EnableEventQueue is true. */ - static const bool EventQueueingActiveByDefault = true; + static constexpr bool EventQueueingActiveByDefault = true; /** * Specifies whether the EBus supports queueing functions which take reference @@ -168,7 +165,7 @@ namespace AZ * You should only use this if you know that the data being passed as arguments will * outlive the dispatch of the queued event. */ - static const bool EnableQueuedReferences = false; + static constexpr bool EnableQueuedReferences = false; /** * Locking primitive that is used when adding and removing @@ -197,7 +194,7 @@ namespace AZ * to do. * By default, the standard policy is used, which locks around all dispatches */ - static const bool LocklessDispatch = false; + static constexpr bool LocklessDispatch = false; /** * Specifies where EBus data is stored. diff --git a/Code/Framework/AzCore/AzCore/EBus/IEventScheduler.h b/Code/Framework/AzCore/AzCore/EBus/IEventScheduler.h index 5c1bbf6dab..021e8edfab 100644 --- a/Code/Framework/AzCore/AzCore/EBus/IEventScheduler.h +++ b/Code/Framework/AzCore/AzCore/EBus/IEventScheduler.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace AZ { diff --git a/Code/Framework/AzCore/AzCore/EBus/Policies.h b/Code/Framework/AzCore/AzCore/EBus/Policies.h index db11043ef8..86cbe5d02f 100644 --- a/Code/Framework/AzCore/AzCore/EBus/Policies.h +++ b/Code/Framework/AzCore/AzCore/EBus/Policies.h @@ -18,9 +18,8 @@ #include #include #include +#include -#include -#include namespace AZ { @@ -251,29 +250,21 @@ namespace AZ void Execute() { AZ_Warning("System", m_isActive, "You are calling execute queued functions on a bus which has not activated its function queuing! Call YourBus::AllowFunctionQueuing(true)!"); - while (true) + + MessageQueueType localMessages; + + // Swap the current list of queue functions with a local instance { - BusMessageCall invoke; + AZStd::scoped_lock lock(m_messagesMutex); + AZStd::swap(localMessages, m_messages); + } - ////////////////////////////////////////////////////////////////////////// - // Pop element from the queue. - { - AZStd::lock_guard lock(m_messagesMutex); - size_t numMessages = m_messages.size(); - if (numMessages == 0) - { - break; - } - AZStd::swap(invoke, m_messages.front()); - m_messages.pop(); - if (numMessages == 1) - { - m_messages = {}; - } - } - ////////////////////////////////////////////////////////////////////////// - - invoke(); + // Execute the queue functions safely now that are owned by the function + while (!localMessages.empty()) + { + const BusMessageCall& localMessage = localMessages.front(); + localMessage(); + localMessages.pop(); } } diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h index 0a1af21213..7f48f301aa 100644 --- a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h +++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index caa4cda8f5..3e6376323c 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -366,6 +366,42 @@ namespace UnitTest }; + static constexpr AZStd::chrono::seconds MaxDispatchTimeoutSeconds = BaseAssetManagerTest::DefaultTimeoutSeconds * 12; + + template + bool DispatchEventsUntilCondition(AZ::Data::AssetManager& assetManager, Pred&& conditionPredicate, + AZStd::chrono::seconds logIntervalSeconds = BaseAssetManagerTest::DefaultTimeoutSeconds, + AZStd::chrono::seconds maxTimeoutSeconds = MaxDispatchTimeoutSeconds) + { + // If the Max Timeout is hit the test will be marked as a failure + + AZStd::chrono::time_point dispatchEventTimeStart = AZStd::chrono::system_clock::now(); + AZStd::chrono::seconds dispatchEventNextLogTime = logIntervalSeconds; + + while (!conditionPredicate()) + { + AZStd::chrono::time_point currentTime = AZStd::chrono::system_clock::now(); + if (AZStd::chrono::seconds elapsedTime{ currentTime - dispatchEventTimeStart }; + elapsedTime >= dispatchEventNextLogTime) + { + const testing::TestInfo* test_info = ::testing::UnitTest::GetInstance()->current_test_info(); + AZ_Printf("AssetManagerLoadingTest", "The DispatchEventsUntiTimeout function has been waiting for %llu seconds" + " in test %s.%s", elapsedTime.count(), test_info->test_case_name(), test_info->name()); + // Update the next log time to be the next multiple of DefaultTimeout Seconds + // after current elapsed time + dispatchEventNextLogTime = elapsedTime + logIntervalSeconds - ((elapsedTime + logIntervalSeconds) % logIntervalSeconds); + if (elapsedTime >= maxTimeoutSeconds) + { + return false; + } + } + assetManager.DispatchEvents(); + AZStd::this_thread::yield(); + } + + return true; + } + #if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_ASSET_MANAGER_FLOOD_TEST TEST_F(AssetJobsFloodTest, DISABLED_FloodTest) #else @@ -1358,42 +1394,74 @@ namespace UnitTest m_assetHandlerAndCatalog->m_numCreations = 0; m_assetHandlerAndCatalog->m_numDestructions = 0; { + ContainerReadyListener containerLoadingCompleteListener(NoLoadAssetId); OnAssetReadyListener readyListener(NoLoadAssetId, azrtti_typeid()); - OnAssetReadyListener depenencyListener(MyAsset2Id, azrtti_typeid()); + OnAssetReadyListener dependencyListener(MyAsset2Id, azrtti_typeid()); + + SCOPED_TRACE("LoadDependencies_BehaviorObeyed"); + + auto AssetOnlyReady = [&readyListener]() -> bool + { + return readyListener.m_ready; + }; + auto AssetAndDependencyReady = [&readyListener, &dependencyListener]() -> bool + { + return readyListener.m_ready && dependencyListener.m_ready; + }; + auto AssetContainerReady = [&containerLoadingCompleteListener]() -> bool + { + return containerLoadingCompleteListener.m_ready; + }; auto noLoadRef = m_testAssetManager->GetAsset(NoLoadAssetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default); - auto maxTimeout = AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds; + // Dispatch AssetBus events until the NoLoadAssetId has signaled an OnAssetReady + // event or the timeout has been reached + EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetOnlyReady)) + << "The DispatchEventsUntiTimeout function has not completed in " + << MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n"; + + // Dispatch AssetBus events until the asset container used to load + // NoLoadAssetId has signaled an OnAssetContainerReady event + // or the timeout has been reached + // Wait until the current asset container has finished loading the NoLoadAssetId + // before trigger another load + // If the wait does not occur here, most likely what would occur is + // the AssetManager::m_ownedAssetContainers object is still loading the NoLoadAssetId + // using the default AssetLoadParameters + // If a call to GetAsset occurs at this point while the Asset is still loading + // it will ignore the new loadParams below and instead just re-use the existing + // AssetContainerReader instance, resulting in the dependent MyAsset2Id not + // being loaded + // The function that can return an existing AssetContainer instance is the + // AssetManager::GetAssetContainer. Since it can be in the middle of a load, + // updating the AssetLoadParams would have an effect on the current in progress + // load + EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetContainerReady)) + << "The DispatchEventsUntiTimeout function has not completed in " + << MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n"; + + // Reset the ContainerLoadingComplete ready status back to 0 + containerLoadingCompleteListener.m_ready = 0; - while (!readyListener.m_ready) - { - m_testAssetManager->DispatchEvents(); - if (AZStd::chrono::system_clock::now() > maxTimeout) - { - break; - } - AZStd::this_thread::yield(); - } - EXPECT_EQ(readyListener.m_ready, 1); - EXPECT_EQ(depenencyListener.m_ready, 0); - AZ::Data::AssetLoadParameters loadParams(nullptr, AZ::Data::AssetDependencyLoadRules::LoadAll); loadParams.m_reloadMissingDependencies = true; auto loadDependencyRef = m_testAssetManager->GetAsset(NoLoadAssetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default, loadParams); - while (!depenencyListener.m_ready || !readyListener.m_ready) - { - m_testAssetManager->DispatchEvents(); - if (AZStd::chrono::system_clock::now() > maxTimeout) - { - break; - } - AZStd::this_thread::yield(); - } + // Dispatch AssetBus events until the NoLoadAssetId and the MyAsset2Id has signaled + // an OnAssetReady event or the timeout has been reached + EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetAndDependencyReady)) + << "The DispatchEventsUntiTimeout function has not completed in " + << MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n"; + EXPECT_EQ(readyListener.m_ready, 1); - EXPECT_EQ(depenencyListener.m_ready, 1); + EXPECT_EQ(dependencyListener.m_ready, 1); + + EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetContainerReady)) + << "The DispatchEventsUntiTimeout function has not completed in " + << MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n"; } CheckFinishedCreationsAndDestructions(); diff --git a/Code/Framework/AzCore/Tests/UUIDTests.cpp b/Code/Framework/AzCore/Tests/UUIDTests.cpp index 5d4fb7a711..a18dc33c4f 100644 --- a/Code/Framework/AzCore/Tests/UUIDTests.cpp +++ b/Code/Framework/AzCore/Tests/UUIDTests.cpp @@ -7,6 +7,7 @@ */ #include #include +#include using namespace AZ; diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.h b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.h index 646410f8db..ae1e3dfa9c 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Logging/MissingAssetLogger.h b/Code/Framework/AzFramework/AzFramework/Logging/MissingAssetLogger.h index 9434ca80ae..b49609d820 100644 --- a/Code/Framework/AzFramework/AzFramework/Logging/MissingAssetLogger.h +++ b/Code/Framework/AzFramework/AzFramework/Logging/MissingAssetLogger.h @@ -8,6 +8,7 @@ #pragma once +#include #include namespace AzFramework { class LogFile; } diff --git a/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionStructures.h b/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionStructures.h index 11c3fedb2b..9d6cd48102 100644 --- a/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionStructures.h +++ b/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionStructures.h @@ -11,6 +11,7 @@ #include #include #include +#include #include //! Common structures for Render geometry queries diff --git a/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h b/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h index 7479b0d1e1..0eb699475f 100644 --- a/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h +++ b/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpConnectionSet.h b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpConnectionSet.h index 8594bf87db..7fa66b0470 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpConnectionSet.h +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpConnectionSet.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace AzNetworking { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h index e2929c0d3e..7b94108a91 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h index d765d4e1e5..685770dd20 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h index a2b004763b..06e9c82e55 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/SourceControlAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/SourceControlAPI.h index df9b136752..5eb4a31ffb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/SourceControlAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/SourceControlAPI.h @@ -10,6 +10,7 @@ #include #include +#include #include namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h index 0500a80c36..888be6b3e0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h @@ -8,6 +8,7 @@ #pragma once +#include #include namespace AzToolsFramework::ViewportUi::Internal diff --git a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.h b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.h index 209897fd6e..8358bc3d2e 100644 --- a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.h +++ b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.h @@ -11,6 +11,7 @@ #if !defined(Q_MOC_RUN) #include "UnitTestRunner.h" #include "native/utilities/IniConfiguration.h" +#include #include #endif diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 9ae3cc2c87..b9369b5bb0 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include diff --git a/Code/Tools/Standalone/Source/LUA/LUAEditorStyleMessages.h b/Code/Tools/Standalone/Source/LUA/LUAEditorStyleMessages.h index 6ddc462e94..cf27245682 100644 --- a/Code/Tools/Standalone/Source/LUA/LUAEditorStyleMessages.h +++ b/Code/Tools/Standalone/Source/LUA/LUAEditorStyleMessages.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthBus.h b/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthBus.h index 4e625a563c..63d5bb2a83 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthBus.h +++ b/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthBus.h @@ -9,6 +9,8 @@ #include +#include + namespace Aws { namespace CognitoIdentityProvider diff --git a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h index f0b9b45aff..39e96517a7 100644 --- a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h +++ b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h @@ -9,6 +9,7 @@ #include #include +#include #include diff --git a/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.cpp b/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.cpp index f111b972e4..798da14aa1 100644 --- a/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.cpp +++ b/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include /////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ThreadLocalContext.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ThreadLocalContext.h index dbea45c54a..4d3534b845 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ThreadLocalContext.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ThreadLocalContext.h @@ -11,6 +11,7 @@ #include #include +#include namespace AZ { diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h index dd42f79106..c56da58ff1 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #endif diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h index 2d05a68771..d1027daa36 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include #include diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/StateControllers/StateController.h b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/StateControllers/StateController.h index 053ed98978..54dccb8ae0 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/StateControllers/StateController.h +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/StateControllers/StateController.h @@ -8,6 +8,7 @@ #pragma once #include +#include // A configurable queue that allows for multiple sources to try to control a single value in a configurable way // such that each object can control the object independently of the other systems, while still maintaining a reasonable state. diff --git a/Gems/ScriptCanvasDeveloper/Code/Editor/Include/ScriptCanvasDeveloperEditor/EditorAutomation/EditorAutomationTest.h b/Gems/ScriptCanvasDeveloper/Code/Editor/Include/ScriptCanvasDeveloperEditor/EditorAutomation/EditorAutomationTest.h index 4a3ba89832..1e4fb27831 100644 --- a/Gems/ScriptCanvasDeveloper/Code/Editor/Include/ScriptCanvasDeveloperEditor/EditorAutomation/EditorAutomationTest.h +++ b/Gems/ScriptCanvasDeveloper/Code/Editor/Include/ScriptCanvasDeveloperEditor/EditorAutomation/EditorAutomationTest.h @@ -11,6 +11,7 @@ #include #include +#include #include #include From 615b53df50785b5a96f80d18cd805282af233441 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 29 Sep 2021 16:26:14 -0700 Subject: [PATCH 080/115] fix bad unused variable component property check Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilder.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index 9c3cdca3e8..5e97bf4aec 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -181,12 +181,15 @@ namespace ScriptCanvasBuilder continue; } - // copy to override unused list for editor display - m_overridesUnused.push_back(*graphVariable); - auto& overrideValue = m_overridesUnused.back(); - overrideValue.DeepCopy(*graphVariable); - overrideValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide); - overrideValue.SetAllowSignalOnChange(false); + if (graphVariable->IsComponentProperty()) + { + // copy to override unused list for editor display + m_overridesUnused.push_back(*graphVariable); + auto& overrideValue = m_overridesUnused.back(); + overrideValue.DeepCopy(*graphVariable); + overrideValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide); + overrideValue.SetAllowSignalOnChange(false); + } } } From 19bd934a43b5d7988c86d48cf16f3399943903ca Mon Sep 17 00:00:00 2001 From: Steve Pham Date: Wed, 29 Sep 2021 17:56:06 -0700 Subject: [PATCH 081/115] Fix missing include for AZStd::unordered_set in AssetEditorBus.h Signed-off-by: Steve Pham --- .../AzToolsFramework/AssetEditor/AssetEditorBus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.h index becdba44ea..9b12ea27d4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorBus.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace AZ::Data { From 27c7e2dcb0b3f823fee9a84cee75a630ff724130 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 29 Sep 2021 19:13:30 -0700 Subject: [PATCH 082/115] Add correct include in FocusModeInterface to fix non-Unity builds. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzToolsFramework/FocusMode/FocusModeInterface.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h index a1047d4207..75e3bab60f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h @@ -12,6 +12,8 @@ #include #include +#include + namespace AzToolsFramework { //! FocusModeInterface From acea5b7da857a06c4da1cf592b120149fa18511f Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Thu, 30 Sep 2021 09:12:41 +0200 Subject: [PATCH 083/115] Animation Editor: Creating Motion Sets does not increment them correctly (#4368) Signed-off-by: Benjamin Jillich --- Gems/EMotionFX/Code/EMotionFX/Source/MotionSet.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/MotionSet.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/MotionSet.cpp index d8880f6fcc..56f7ee567e 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/MotionSet.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/MotionSet.cpp @@ -726,10 +726,12 @@ namespace EMotionFX { MCore::LockGuardRecursive lock(m_mutex); - return AZStd::accumulate(begin(m_childSets), end(m_childSets), size_t{0}, [](size_t total, const MotionSet* motionSet) + size_t result = 0; + for (const MotionSet* motionSet : m_childSets) { - return total + motionSet->GetIsOwnedByRuntime(); - }); + result += !motionSet->GetIsOwnedByRuntime(); + } + return result; } From ab0aa4973f2ec40f1a02ad1476521e55f95d8091 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Thu, 30 Sep 2021 08:43:48 +0100 Subject: [PATCH 084/115] Remove camera LookAtAfterInterpolation (#4391) Signed-off-by: hultonha --- .../EditorModularViewportCameraComposer.cpp | 18 +++------------- Code/Editor/EditorViewportCamera.cpp | 2 +- .../Lib/Tests/Camera/test_EditorCamera.cpp | 4 ++-- .../SandboxIntegration.cpp | 3 +-- .../ModularViewportCameraController.h | 8 +++---- ...odularViewportCameraControllerRequestBus.h | 6 +----- .../ModularViewportCameraController.cpp | 21 +------------------ 7 files changed, 12 insertions(+), 50 deletions(-) diff --git a/Code/Editor/EditorModularViewportCameraComposer.cpp b/Code/Editor/EditorModularViewportCameraComposer.cpp index 600f2089e6..29cf348ab5 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.cpp +++ b/Code/Editor/EditorModularViewportCameraComposer.cpp @@ -175,27 +175,15 @@ namespace SandboxEditor m_pivotCamera = AZStd::make_shared(SandboxEditor::CameraPivotChannelId()); m_pivotCamera->SetPivotFn( - [viewportId = m_viewportId]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) + []([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) { - AZStd::optional lookAtAfterInterpolation; - AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult( - lookAtAfterInterpolation, viewportId, - &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::LookAtAfterInterpolation); - - // initially attempt to use the last set look at point after an interpolation has finished - // note: ignore this if it is the same location as the camera (e.g. after go to position) - if (lookAtAfterInterpolation.has_value() && !lookAtAfterInterpolation->IsClose(position)) - { - return *lookAtAfterInterpolation; - } - - // otherwise fall back to the selected entity pivot + // use the manipulator transform as the pivot point AZStd::optional entityPivot; AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( entityPivot, AzToolsFramework::GetEntityContextId(), &AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform); - // finally just use the identity + // otherwise just use the identity return entityPivot.value_or(AZ::Transform::CreateIdentity()).GetTranslation(); }); diff --git a/Code/Editor/EditorViewportCamera.cpp b/Code/Editor/EditorViewportCamera.cpp index 0c7a1559d1..b25e7072ff 100644 --- a/Code/Editor/EditorViewportCamera.cpp +++ b/Code/Editor/EditorViewportCamera.cpp @@ -48,7 +48,7 @@ namespace SandboxEditor { AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( viewportContext->GetId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, - AZ::Transform::CreateFromQuaternionAndTranslation(CameraRotation(pitch, yaw), position), 0.0f); + AZ::Transform::CreateFromQuaternionAndTranslation(CameraRotation(pitch, yaw), position)); } } diff --git a/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp b/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp index affe5794cc..1a44d43370 100644 --- a/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp +++ b/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp @@ -167,7 +167,7 @@ namespace UnitTest AZ::Quaternion::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(20.0f, 40.0f, 60.0f)); AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, - transformToInterpolateTo, 0.0f); + transformToInterpolateTo); // simulate interpolation m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() }); @@ -193,7 +193,7 @@ namespace UnitTest // When AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, - transformToInterpolateTo, 0.0f); + transformToInterpolateTo); // simulate interpolation m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() }); diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index 47bd214b8d..666700a874 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -1739,8 +1739,7 @@ void SandboxIntegrationManager::GoToEntitiesInViewports(const AzToolsFramework:: AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( viewportContext->GetId(), - &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform, - distanceToLookAt); + &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform); } } } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h index 32897ab4d9..1200cb3d79 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -112,8 +112,7 @@ namespace AtomToolsFramework void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override; // ModularViewportCameraControllerRequestBus overrides ... - void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) override; - AZStd::optional LookAtAfterInterpolation() const override; + void InterpolateToTransform(const AZ::Transform& worldFromLocal) override; AZ::Transform GetReferenceFrame() const override; void SetReferenceFrame(const AZ::Transform& worldFromLocal) override; void ClearReferenceFrame() override; @@ -149,9 +148,8 @@ namespace AtomToolsFramework CameraAnimation m_cameraAnimation; //!< Camera animation state (used during CameraMode::Animation). CameraMode m_cameraMode = CameraMode::Control; //!< The current mode the camera is operating in. - AZStd::optional m_lookAtAfterInterpolation; //!< The look at point after an interpolation has finished. - //!< Will be cleared when the view changes (camera looks away). - AZ::Transform m_referenceFrameOverride = AZ::Transform::CreateIdentity(); //!< + //! An additional reference frame the camera can operate in (identity has no effect). + AZ::Transform m_referenceFrameOverride = AZ::Transform::CreateIdentity(); //! Flag to prevent circular updates of the camera transform (while the viewport transform is being updated internally). bool m_updatingTransformInternally = false; //! Listen for camera view changes outside of the camera controller. diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h index 388d24164a..ab397692e4 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h @@ -29,11 +29,7 @@ namespace AtomToolsFramework //! Begin a smooth transition of the camera to the requested transform. //! @param worldFromLocal The transform of where the camera should end up. - //! @param lookAtDistance The distance between the camera transform and the imagined look at point. - virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) = 0; - - //! Look at point after an interpolation has finished and no translation has occurred. - virtual AZStd::optional LookAtAfterInterpolation() const = 0; + virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal) = 0; //! Return the current reference frame. //! @note If a reference frame has not been set or a frame has been cleared, this is just the identity. diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp index 0bdd6fb55c..a92bfdbcdb 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -227,19 +227,6 @@ namespace AtomToolsFramework { m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count()); m_camera = AzFramework::SmoothCamera(m_camera, m_targetCamera, m_cameraProps, event.m_deltaTime.count()); - - // if there has been an interpolation, only clear the look at point if it is no longer - // centered in the view (the camera has looked away from it) - if (m_lookAtAfterInterpolation.has_value()) - { - if (const float lookDirection = - (*m_lookAtAfterInterpolation - m_camera.Translation()).GetNormalized().Dot(m_camera.Transform().GetBasisY()); - !AZ::IsCloseMag(lookDirection, 1.0f, 0.001f)) - { - m_lookAtAfterInterpolation = {}; - } - } - m_modularCameraViewportContext->SetCameraTransform(m_referenceFrameOverride * m_camera.Transform()); } else if (m_cameraMode == CameraMode::Animation) @@ -277,16 +264,10 @@ namespace AtomToolsFramework m_updatingTransformInternally = false; } - void ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance) + void ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal) { m_cameraMode = CameraMode::Animation; m_cameraAnimation = CameraAnimation{ m_referenceFrameOverride * m_camera.Transform(), worldFromLocal, 0.0f }; - m_lookAtAfterInterpolation = worldFromLocal.GetTranslation() + worldFromLocal.GetBasisY() * lookAtDistance; - } - - AZStd::optional ModularViewportCameraControllerInstance::LookAtAfterInterpolation() const - { - return m_lookAtAfterInterpolation; } AZ::Transform ModularViewportCameraControllerInstance::GetReferenceFrame() const From 9eb9a13d9986530a79699433753bacf8d06984c0 Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Thu, 30 Sep 2021 10:38:45 +0200 Subject: [PATCH 085/115] Flipped CVar to activate the AssetBrowser Search View (#4370) Signed-off-by: igarri --- .../AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp | 2 +- .../AssetBrowser/AssetPicker/AssetPickerDialog.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp index acf935e6dc..c6772ea2d7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp @@ -20,7 +20,7 @@ AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") AZ_POP_DISABLE_WARNING AZ_CVAR( - bool, ed_useNewAssetBrowserTableView, false, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, ed_useNewAssetBrowserTableView, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Use the new AssetBrowser TableView for searching assets."); namespace AzToolsFramework { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp index 966cd5a43a..4ebeb03a71 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp @@ -29,7 +29,7 @@ AZ_PUSH_DISABLE_WARNING(4251 4244, "-Wunknown-warning-option") // disable warnin AZ_POP_DISABLE_WARNING AZ_CVAR( - bool, ed_hideAssetPickerPathColumn, false, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, ed_hideAssetPickerPathColumn, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Hide AssetPicker path column for a clearer view."); AZ_CVAR_EXTERNED(bool, ed_useNewAssetBrowserTableView); From 43748c37fd26f86fefb42b1fdf96407cdfbb50e6 Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Thu, 30 Sep 2021 13:39:22 +0100 Subject: [PATCH 086/115] update joints to use cluster viewport ui. (#4352) also some joints Component mode cleanup. Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com> --- .../img/UI20/toolbar/joints/Damping.svg | 18 + .../img/UI20/toolbar/joints/MaxForce.svg | 22 + .../img/UI20/toolbar/joints/MaxTorque.svg | 15 + .../img/UI20/toolbar/joints/SnapPosition.svg | 19 + .../img/UI20/toolbar/joints/SnapRotation.svg | 17 + .../img/UI20/toolbar/joints/Stiffness.svg | 22 + .../img/UI20/toolbar/joints/SwingLimits.svg | 22 + .../img/UI20/toolbar/joints/TwistLimits.svg | 18 + .../AzQtComponents/Components/resources.qrc | 8 + .../ViewportUi/ButtonGroup.cpp | 24 +- .../AzToolsFramework/ViewportUi/ButtonGroup.h | 2 + .../ViewportUi/ViewportUiManager.cpp | 10 + .../ViewportUi/ViewportUiManager.h | 1 + .../ViewportUi/ViewportUiRequestBus.h | 2 + .../Tests/Viewport/ViewportUiManagerTests.cpp | 19 + .../Code/Editor/ColliderAssetScaleMode.h | 7 +- Gems/PhysX/Code/Editor/ColliderBoxMode.h | 7 +- Gems/PhysX/Code/Editor/ColliderCapsuleMode.h | 6 +- .../Code/Editor/ColliderComponentMode.cpp | 2 +- .../PhysX/Code/Editor/ColliderComponentMode.h | 4 +- Gems/PhysX/Code/Editor/ColliderOffsetMode.h | 7 +- Gems/PhysX/Code/Editor/ColliderRotationMode.h | 6 +- Gems/PhysX/Code/Editor/ColliderSphereMode.h | 6 +- .../Code/Editor/ColliderSubComponentMode.h | 42 -- Gems/PhysX/Code/Editor/EditorJointCommon.h | 17 + .../Code/Editor/EditorJointComponentMode.cpp | 577 ----------------- .../Code/Editor/EditorJointComponentMode.h | 173 ----- .../Code/Editor/EditorJointTypeDrawer.cpp | 68 -- .../PhysX/Code/Editor/EditorJointTypeDrawer.h | 41 -- .../Code/Editor/EditorJointTypeDrawerBus.h | 31 - .../EditorSubComponentModeAngleCone.cpp | 453 ------------- .../Editor/EditorSubComponentModeAngleCone.h | 63 -- .../EditorSubComponentModeAnglePair.cpp | 318 --------- .../Editor/EditorSubComponentModeAnglePair.h | 66 -- .../Editor/EditorSubComponentModeBase.cpp | 37 -- .../Code/Editor/EditorSubComponentModeBase.h | 55 -- .../Editor/EditorSubComponentModeLinear.cpp | 133 ---- .../Editor/EditorSubComponentModeLinear.h | 46 -- .../Editor/EditorSubComponentModeRotation.cpp | 151 ----- .../Editor/EditorSubComponentModeRotation.h | 48 -- .../EditorSubComponentModeSnapPosition.cpp | 97 --- .../EditorSubComponentModeSnapPosition.h | 42 -- .../EditorSubComponentModeSnapRotation.cpp | 122 ---- .../EditorSubComponentModeSnapRotation.h | 38 -- .../Editor/EditorSubComponentModeVec3.cpp | 91 --- .../Code/Editor/EditorSubComponentModeVec3.h | 34 - .../Joints/JointsComponentMode.cpp | 601 ++++++++++++++++++ .../Joints/JointsComponentMode.h | 79 +++ .../Joints/JointsComponentModeCommon.cpp | 27 + .../Joints/JointsComponentModeCommon.h | 70 ++ .../JointsSubComponentModeAngleCone.cpp | 432 +++++++++++++ .../Joints/JointsSubComponentModeAngleCone.h | 69 ++ .../JointsSubComponentModeAnglePair.cpp | 305 +++++++++ .../Joints/JointsSubComponentModeAnglePair.h | 70 ++ .../JointsSubComponentModeLinearFloat.cpp | 133 ++++ .../JointsSubComponentModeLinearFloat.h | 56 ++ .../Joints/JointsSubComponentModeRotation.cpp | 134 ++++ .../Joints/JointsSubComponentModeRotation.h | 44 ++ .../Joints/JointsSubComponentModeSnap.cpp} | 135 ++-- .../Joints/JointsSubComponentModeSnap.h} | 56 +- .../JointsSubComponentModeSnapPosition.cpp | 91 +++ .../JointsSubComponentModeSnapPosition.h | 42 ++ .../JointsSubComponentModeSnapRotation.cpp | 117 ++++ .../JointsSubComponentModeSnapRotation.h | 41 ++ .../JointsSubComponentModeTranslate.cpp | 90 +++ .../Joints/JointsSubComponentModeTranslate.h | 43 ++ .../PhysXSubComponentModeBase.h | 48 ++ .../PhysX/Code/Include/PhysX/EditorJointBus.h | 45 +- .../Code/Source/EditorBallJointComponent.cpp | 93 +-- .../Code/Source/EditorBallJointComponent.h | 2 +- .../Code/Source/EditorFixedJointComponent.cpp | 12 +- .../Code/Source/EditorFixedJointComponent.h | 3 + .../Code/Source/EditorHingeJointComponent.cpp | 85 ++- .../Code/Source/EditorHingeJointComponent.h | 2 +- .../Code/Source/EditorJointComponent.cpp | 52 +- Gems/PhysX/Code/Source/EditorJointComponent.h | 2 +- Gems/PhysX/Code/physx_editor_files.cmake | 46 +- 77 files changed, 3006 insertions(+), 3026 deletions(-) create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Damping.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxForce.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxTorque.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapPosition.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapRotation.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Stiffness.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SwingLimits.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/TwistLimits.svg delete mode 100644 Gems/PhysX/Code/Editor/ColliderSubComponentMode.h create mode 100644 Gems/PhysX/Code/Editor/EditorJointCommon.h delete mode 100644 Gems/PhysX/Code/Editor/EditorJointComponentMode.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorJointComponentMode.h delete mode 100644 Gems/PhysX/Code/Editor/EditorJointTypeDrawer.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorJointTypeDrawer.h delete mode 100644 Gems/PhysX/Code/Editor/EditorJointTypeDrawerBus.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeBase.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeBase.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.h rename Gems/PhysX/Code/Editor/{EditorSubComponentModeSnap.cpp => Source/ComponentModes/Joints/JointsSubComponentModeSnap.cpp} (71%) rename Gems/PhysX/Code/Editor/{EditorSubComponentModeSnap.h => Source/ComponentModes/Joints/JointsSubComponentModeSnap.h} (51%) create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/PhysXSubComponentModeBase.h diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Damping.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Damping.svg new file mode 100644 index 0000000000..b12640bd59 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Damping.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxForce.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxForce.svg new file mode 100644 index 0000000000..b1b09104b1 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxForce.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxTorque.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxTorque.svg new file mode 100644 index 0000000000..3c40cb82b2 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxTorque.svg @@ -0,0 +1,15 @@ + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapPosition.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapPosition.svg new file mode 100644 index 0000000000..a9c5811d7d --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapPosition.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapRotation.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapRotation.svg new file mode 100644 index 0000000000..684c32a08d --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapRotation.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Stiffness.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Stiffness.svg new file mode 100644 index 0000000000..456785f1bc --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Stiffness.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SwingLimits.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SwingLimits.svg new file mode 100644 index 0000000000..ec3d1114bb --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SwingLimits.svg @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/TwistLimits.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/TwistLimits.svg new file mode 100644 index 0000000000..98f56f547d --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/TwistLimits.svg @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc index 7321128b57..16d55f1b8c 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc @@ -390,6 +390,14 @@ img/UI20/toolbar/Y_axis.svg img/UI20/toolbar/Z_axis.svg img/UI20/toolbar/XY2_copy.svg + img/UI20/toolbar/joints/Damping.svg + img/UI20/toolbar/joints/MaxForce.svg + img/UI20/toolbar/joints/MaxTorque.svg + img/UI20/toolbar/joints/SnapPosition.svg + img/UI20/toolbar/joints/SnapRotation.svg + img/UI20/toolbar/joints/Stiffness.svg + img/UI20/toolbar/joints/SwingLimits.svg + img/UI20/toolbar/joints/TwistLimits.svg img/triangle0.png img/triangle0_highlighted.png img/line.png diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.cpp index e933940d95..372587c110 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.cpp @@ -29,13 +29,29 @@ namespace AzToolsFramework::ViewportUi::Internal void ButtonGroup::SetHighlightedButton(ButtonId buttonId) { + if (buttonId == m_highlightedButtonId) // the requested button is highlighted, so do nothing. + { + return; + } + if (auto buttonEntry = m_buttons.find(buttonId); buttonEntry != m_buttons.end()) { - for (auto& button : m_buttons) - { - button.second->m_state = Button::State::Deselected; - } + ClearHighlightedButton(); buttonEntry->second->m_state = Button::State::Selected; + m_highlightedButtonId = buttonId; + } + } + + void ButtonGroup::ClearHighlightedButton() + { + if (m_highlightedButtonId == InvalidButtonId) + { + return; + } + if (auto buttonEntry = m_buttons.find(m_highlightedButtonId); buttonEntry != m_buttons.end()) + { + buttonEntry->second->m_state = Button::State::Deselected; + m_highlightedButtonId = InvalidButtonId; } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h index 888be6b3e0..7b6864a71b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h @@ -25,6 +25,7 @@ namespace AzToolsFramework::ViewportUi::Internal ~ButtonGroup() = default; void SetHighlightedButton(ButtonId buttonId); + void ClearHighlightedButton(); void SetViewportUiElementId(ViewportUiElementId id); ViewportUiElementId GetViewportUiElementId() const; @@ -40,5 +41,6 @@ namespace AzToolsFramework::ViewportUi::Internal AZ::Event m_buttonTriggeredEvent; ViewportUiElementId m_viewportUiId; AZStd::unordered_map> m_buttons; + ButtonId m_highlightedButtonId = InvalidButtonId; }; } // namespace AzToolsFramework::ViewportUi::Internal diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp index cee4a311e8..255d11f561 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp @@ -50,6 +50,16 @@ namespace AzToolsFramework::ViewportUi } } + void ViewportUiManager::ClearClusterActiveButton(ClusterId clusterId) + { + if (auto clusterIt = m_clusterButtonGroups.find(clusterId); clusterIt != m_clusterButtonGroups.end()) + { + auto cluster = clusterIt->second; + cluster->ClearHighlightedButton(); + UpdateButtonGroupUi(cluster.get()); + } + } + void ViewportUiManager::SetSwitcherActiveButton(const SwitcherId switcherId, const ButtonId buttonId) { if (auto switcherIt = m_switcherButtonGroups.find(switcherId); switcherIt != m_switcherButtonGroups.end()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h index c5ecf7aee6..9ec6648451 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h @@ -30,6 +30,7 @@ namespace AzToolsFramework::ViewportUi const ClusterId CreateCluster(Alignment align) override; const SwitcherId CreateSwitcher(Alignment align) override; void SetClusterActiveButton(ClusterId clusterId, ButtonId buttonId) override; + void ClearClusterActiveButton(ClusterId clusterId) override; void SetSwitcherActiveButton(SwitcherId switcherId, ButtonId buttonId) override; void SetClusterButtonLocked(ClusterId clusterId, ButtonId buttonId, bool isLocked) override; void SetClusterButtonTooltip(ClusterId clusterId, ButtonId buttonId, const AZStd::string& tooltip) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h index 649186c7e7..108d23950a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h @@ -59,6 +59,8 @@ namespace AzToolsFramework::ViewportUi virtual const SwitcherId CreateSwitcher(Alignment align) = 0; //! Sets the active button of the cluster. This is the button which will display as highlighted. virtual void SetClusterActiveButton(ClusterId clusterId, ButtonId buttonId) = 0; + //! Clears the active button of the cluster if one is active. The button will no longer display as highlighted. + virtual void ClearClusterActiveButton(ClusterId clusterId) = 0; //! Sets the active button of the switcher. This is the button which has a text label. virtual void SetSwitcherActiveButton(SwitcherId clusterId, ButtonId buttonId) = 0; //! Adds a locked overlay to the cluster button's icon. diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportUiManagerTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportUiManagerTests.cpp index 676b9c5e35..daf4b9c29a 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportUiManagerTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportUiManagerTests.cpp @@ -127,6 +127,25 @@ namespace UnitTest EXPECT_TRUE(button->m_state == AzToolsFramework::ViewportUi::Internal::Button::State::Selected); } + TEST_F(ViewportUiManagerTestFixture, ClearClusterActiveButtonSetsButtonStateToDeselected) + { + // setup + auto clusterId = m_viewportManagerWrapper.GetViewportManager()->CreateCluster(AzToolsFramework::ViewportUi::Alignment::TopLeft); + auto buttonId = m_viewportManagerWrapper.GetViewportManager()->CreateClusterButton(clusterId, ""); + + auto clusterEntry = m_viewportManagerWrapper.GetViewportManager()->GetClusterMap().find(clusterId); + auto button = clusterEntry->second->GetButton(buttonId); + + // first set a button to active + m_viewportManagerWrapper.GetViewportManager()->SetClusterActiveButton(clusterId, buttonId); + EXPECT_TRUE(button->m_state == AzToolsFramework::ViewportUi::Internal::Button::State::Selected); + + // clear the active button on the cluster + m_viewportManagerWrapper.GetViewportManager()->ClearClusterActiveButton(clusterId); + // the button should now be deselected + EXPECT_TRUE(button->m_state == AzToolsFramework::ViewportUi::Internal::Button::State::Deselected); + } + TEST_F(ViewportUiManagerTestFixture, RegisterClusterEventHandlerConnectsHandlerToClusterEvent) { auto clusterId = m_viewportManagerWrapper.GetViewportManager()->CreateCluster(AzToolsFramework::ViewportUi::Alignment::TopLeft); diff --git a/Gems/PhysX/Code/Editor/ColliderAssetScaleMode.h b/Gems/PhysX/Code/Editor/ColliderAssetScaleMode.h index 4659bf3677..24e33ea584 100644 --- a/Gems/PhysX/Code/Editor/ColliderAssetScaleMode.h +++ b/Gems/PhysX/Code/Editor/ColliderAssetScaleMode.h @@ -8,21 +8,20 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include namespace PhysX { /// Sub component mode for modifying the asset scale on a collider in the viewport. - class ColliderAssetScaleMode - : public PhysX::ColliderSubComponentMode + class ColliderAssetScaleMode : public PhysXSubComponentModeBase { public: AZ_CLASS_ALLOCATOR_DECL ColliderAssetScaleMode(); - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderBoxMode.h b/Gems/PhysX/Code/Editor/ColliderBoxMode.h index a8e0c03a3a..75ce928d80 100644 --- a/Gems/PhysX/Code/Editor/ColliderBoxMode.h +++ b/Gems/PhysX/Code/Editor/ColliderBoxMode.h @@ -8,19 +8,18 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include namespace PhysX { /// Sub component mode for modifying the box dimensions on a collider. - class ColliderBoxMode - : public PhysX::ColliderSubComponentMode + class ColliderBoxMode : public PhysXSubComponentModeBase { public: AZ_CLASS_ALLOCATOR_DECL - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderCapsuleMode.h b/Gems/PhysX/Code/Editor/ColliderCapsuleMode.h index b152801988..ceedd84a35 100644 --- a/Gems/PhysX/Code/Editor/ColliderCapsuleMode.h +++ b/Gems/PhysX/Code/Editor/ColliderCapsuleMode.h @@ -8,7 +8,7 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include #include @@ -16,13 +16,13 @@ namespace PhysX { /// Sub component mode for modifying the height and radius on a capsule collider. class ColliderCapsuleMode - : public PhysX::ColliderSubComponentMode + : public PhysXSubComponentModeBase , private AzFramework::EntityDebugDisplayEventBus::Handler { public: AZ_CLASS_ALLOCATOR_DECL - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderComponentMode.cpp b/Gems/PhysX/Code/Editor/ColliderComponentMode.cpp index 994811b8d1..5de625f679 100644 --- a/Gems/PhysX/Code/Editor/ColliderComponentMode.cpp +++ b/Gems/PhysX/Code/Editor/ColliderComponentMode.cpp @@ -7,7 +7,6 @@ */ #include "ColliderComponentMode.h" -#include "ColliderSubComponentMode.h" #include "ColliderOffsetMode.h" #include "ColliderRotationMode.h" #include "ColliderBoxMode.h" @@ -15,6 +14,7 @@ #include "ColliderCapsuleMode.h" #include "ColliderAssetScaleMode.h" +#include #include #include diff --git a/Gems/PhysX/Code/Editor/ColliderComponentMode.h b/Gems/PhysX/Code/Editor/ColliderComponentMode.h index 420e621054..b4ca060065 100644 --- a/Gems/PhysX/Code/Editor/ColliderComponentMode.h +++ b/Gems/PhysX/Code/Editor/ColliderComponentMode.h @@ -15,7 +15,7 @@ namespace PhysX { - class ColliderSubComponentMode; + class PhysXSubComponentModeBase; //! ComponentMode for the Collider Component - Manages a list of Sub-Component Modes and //! is responsible for switching between and activating them. @@ -53,7 +53,7 @@ namespace PhysX void CreateSubModes(); void ResetCurrentMode(); - AZStd::unordered_map> m_subModes; + AZStd::unordered_map> m_subModes; SubMode m_subMode = SubMode::Dimensions; //! Create the Viewport UI cluster for sub mode selection. diff --git a/Gems/PhysX/Code/Editor/ColliderOffsetMode.h b/Gems/PhysX/Code/Editor/ColliderOffsetMode.h index bcf140a5e3..6a2e6a8a12 100644 --- a/Gems/PhysX/Code/Editor/ColliderOffsetMode.h +++ b/Gems/PhysX/Code/Editor/ColliderOffsetMode.h @@ -8,21 +8,20 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include namespace PhysX { /// Sub component mode for modifying offset on a collider in the viewport. - class ColliderOffsetMode - : public PhysX::ColliderSubComponentMode + class ColliderOffsetMode : public PhysXSubComponentModeBase { public: AZ_CLASS_ALLOCATOR_DECL ColliderOffsetMode(); - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderRotationMode.h b/Gems/PhysX/Code/Editor/ColliderRotationMode.h index e1f578aed7..dc37e23b0e 100644 --- a/Gems/PhysX/Code/Editor/ColliderRotationMode.h +++ b/Gems/PhysX/Code/Editor/ColliderRotationMode.h @@ -8,7 +8,7 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include #include @@ -16,7 +16,7 @@ namespace PhysX { /// Sub component mode for modifying the rotation on a collider in the viewport. class ColliderRotationMode - : public PhysX::ColliderSubComponentMode + : public PhysXSubComponentModeBase , private AzFramework::EntityDebugDisplayEventBus::Handler { public: @@ -24,7 +24,7 @@ namespace PhysX ColliderRotationMode(); - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderSphereMode.h b/Gems/PhysX/Code/Editor/ColliderSphereMode.h index 08ee813cd0..7d255d598b 100644 --- a/Gems/PhysX/Code/Editor/ColliderSphereMode.h +++ b/Gems/PhysX/Code/Editor/ColliderSphereMode.h @@ -8,7 +8,7 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include #include @@ -16,13 +16,13 @@ namespace PhysX { /// Sub component mode for modifying the box dimensions on a collider. class ColliderSphereMode - : public PhysX::ColliderSubComponentMode + : public PhysXSubComponentModeBase , private AzFramework::EntityDebugDisplayEventBus::Handler { public: AZ_CLASS_ALLOCATOR_DECL - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderSubComponentMode.h b/Gems/PhysX/Code/Editor/ColliderSubComponentMode.h deleted file mode 100644 index 4711a20c86..0000000000 --- a/Gems/PhysX/Code/Editor/ColliderSubComponentMode.h +++ /dev/null @@ -1,42 +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 - -namespace AZ -{ - class EntityComponentIdPair; -} - -namespace PhysX -{ - /// Interface to implement when adding a new editing mode - /// for collider component mode. - class ColliderSubComponentMode - { - public: - virtual ~ColliderSubComponentMode() {}; - - /// Called when the mode is entered to initialise the mode. - /// @param idPair The entity/component id pair. - virtual void Setup(const AZ::EntityComponentIdPair& idPair) = 0; - - /// Called when the mode needs to refresh it's values. - /// @param idPair The entity/component id pair. - virtual void Refresh(const AZ::EntityComponentIdPair& idPair) = 0; - - /// Called when the mode exits to perform cleanup. - /// @param idPair The entity/component id pair. - virtual void Teardown(const AZ::EntityComponentIdPair& idPair) = 0; - - /// Called when reset hotkey is pressed. - /// Should reset values in the sub component mode to sensible defaults. - /// @param idPair The entity/component id pair. - virtual void ResetValues(const AZ::EntityComponentIdPair& idPair) = 0; - }; -} diff --git a/Gems/PhysX/Code/Editor/EditorJointCommon.h b/Gems/PhysX/Code/Editor/EditorJointCommon.h new file mode 100644 index 0000000000..031b293942 --- /dev/null +++ b/Gems/PhysX/Code/Editor/EditorJointCommon.h @@ -0,0 +1,17 @@ +/* + * 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 PhysX +{ + //! Pair of floating point values for angular limits. + using AngleLimitsFloatPair = AZStd::pair; +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorJointComponentMode.cpp b/Gems/PhysX/Code/Editor/EditorJointComponentMode.cpp deleted file mode 100644 index 39b028bef3..0000000000 --- a/Gems/PhysX/Code/Editor/EditorJointComponentMode.cpp +++ /dev/null @@ -1,577 +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 - -namespace PhysX -{ - namespace - { - //! Uri's for shortcut actions. - const AZ::Crc32 GoToNextModeActionUri = AZ_CRC("com.o3de.action.physx.joint.nextmode", 0xe9cf4ed6); - const AZ::Crc32 GoToPrevModeActionUri = AZ_CRC("com.o3de.action.physx.joint.prevmode", 0xe70f8daa); - } - - const AZStd::string EditorJointComponentMode::s_parameterAngularPair = "Twist Limits"; - const AZStd::string EditorJointComponentMode::s_parameterDamping = "Damping"; - const AZStd::string EditorJointComponentMode::s_parameterMaxForce = "Maximum Force"; - const AZStd::string EditorJointComponentMode::s_parameterMaxTorque = "Maximum Torque"; - const AZStd::string EditorJointComponentMode::s_parameterPosition = "Position"; - const AZStd::string EditorJointComponentMode::s_parameterRotation = "Rotation"; - const AZStd::string EditorJointComponentMode::s_parameterSnapPosition = "Snap Position"; - const AZStd::string EditorJointComponentMode::s_parameterSnapRotation = "Snap Rotation"; - const AZStd::string EditorJointComponentMode::s_parameterStiffness = "Stiffness"; - const AZStd::string EditorJointComponentMode::s_parameterSwingLimit = "Swing Limits"; - const AZStd::string EditorJointComponentMode::s_parameterTolerance = "Tolerance"; - const AZStd::string EditorJointComponentMode::s_parameterTransform = "Transform"; - const AZStd::string EditorJointComponentMode::s_parameterComponentMode = "Component Mode"; - const AZStd::string EditorJointComponentMode::s_parameterLeadEntity = "Lead Entity"; - const AZStd::string EditorJointComponentMode::s_parameterSelectOnSnap = "Select on Snap"; - - EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type) - : m_name(name), m_type(type) - { - } - - EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , float exponent - , float max - , float min) - : m_name(name), m_type(type), m_exponent(exponent), m_max(max), m_min(min) - { - } - - EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , const AZ::Vector3& axis - , float max - , float min) - : m_name(name), m_type(type), m_axis(axis), m_max(max), m_min(min) - { - } - - EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , float max - , float min) - : m_name(name), m_type(type), m_max(max), m_min(min) - { - } - - EditorJointComponentMode::EditorJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) - : EditorBaseComponentMode(entityComponentIdPair, componentType) - , m_entityComponentIdPair(entityComponentIdPair) - , m_componentType(componentType) - { - EditorJointRequestBus::Event( - m_entityComponentIdPair - , &EditorJointRequests::SetBoolValue - , EditorJointComponentMode::s_parameterComponentMode - , true); - } - - EditorJointComponentMode::~EditorJointComponentMode() - { - EditorJointRequestBus::Event( - m_entityComponentIdPair - , &EditorJointRequests::SetBoolValue - , EditorJointComponentMode::s_parameterComponentMode - , false); - } - - bool EditorJointComponentMode::HandleMouseInteraction( - const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) - { - if (mouseInteraction.m_mouseEvent == AzToolsFramework::ViewportInteraction::MouseEvent::Wheel && - mouseInteraction.m_mouseInteraction.m_keyboardModifiers.Ctrl()) - { - NextMode(); - return true; - } - - // Propagate mouse interaction to sub-component mode. - if (m_currentSubComponentMode) - { - m_currentSubComponentMode->HandleMouseInteraction(mouseInteraction); - } - - return false; - } - - AZStd::vector EditorJointComponentMode::PopulateActionsImpl() - { - AzToolsFramework::ActionOverride goToNextMode; - goToNextMode.SetUri(GoToNextModeActionUri); - goToNextMode.SetKeySequence(QKeySequence(Qt::Key_Tab)); - goToNextMode.SetTitle("Next Mode"); - goToNextMode.SetTip("Go to next mode"); - goToNextMode.SetEntityComponentIdPair(GetEntityComponentIdPair()); - goToNextMode.SetCallback([this]() - { - NextMode(); - }); - - AzToolsFramework::ActionOverride goToPrevMode; - goToPrevMode.SetUri(GoToPrevModeActionUri); - goToPrevMode.SetKeySequence(QKeySequence(Qt::SHIFT + Qt::Key_Tab)); - goToPrevMode.SetTitle("Previous Mode"); - goToPrevMode.SetTip("Go to previous mode"); - goToPrevMode.SetEntityComponentIdPair(GetEntityComponentIdPair()); - goToPrevMode.SetCallback([this]() - { - PreviousMode(); - }); - - return {goToNextMode, goToPrevMode}; - } - - void EditorJointComponentMode::NextMode() - { - const bool isForwardChange = true; - ChangeMode(isForwardChange); - } - - void EditorJointComponentMode::PreviousMode() - { - const bool isForwardChange = false; - ChangeMode(isForwardChange); - } - - void EditorJointComponentMode::ChangeMode(bool forwardChange) - { - if (m_configMap.empty()) - { - return; - } - - AZStd::string previousModeName; - if (m_currentSubComponentMode) - { - previousModeName = m_currentSubComponentMode->m_name; - m_currentSubComponentMode.reset(); - } - - ConfigMapIter configIter = m_configMap.begin(); - if (!previousModeName.empty()) - { - configIter = m_configMap.find(previousModeName); - } - - AZ::u32 iterCount = 0; - do - { - if (forwardChange) - { - ++configIter; - if (configIter == m_configMap.end()) - { - configIter = m_configMap.begin(); - } - } - else - { - if (configIter == m_configMap.begin()) - { - configIter = m_configMap.end(); - } - --configIter; - } - ++iterCount; - } while (!IsSubComponentModeUsed(configIter->second.m_name) && iterCount != m_configMap.size()); - - if (iterCount == m_configMap.size()) // All sub component modes are not in use. - { - return; - } - - SetCurrentSubComponentMode(configIter->second.m_name); - } - - void EditorJointComponentMode::SetCurrentSubComponentMode(const AZStd::string& subComponentModeName) - { - ConfigMapIter configIter = m_configMap.find(subComponentModeName); - if (configIter == m_configMap.end()) - { - AZ_Warning("EditorJointComponentMode" - , false - , "Attempt to set sub component mode which does not exist: %s" - , subComponentModeName.c_str()); - return; - } - EditorSubComponentModeConfig config = configIter->second; - - EditorJointRequestBus::EventResult( - config.m_selectLeadOnSnap, m_entityComponentIdPair - , &EditorJointRequests::GetBoolValue - , s_parameterSelectOnSnap); - - m_currentSubComponentMode.reset(); - - switch (config.m_type) - { - case EditorSubComponentModeType::Linear: - SetSubComponentModeLinear(config); - break; - case EditorSubComponentModeType::AnglePair: - SetSubComponentModeAnglePair(config); - break; - case EditorSubComponentModeType::AngleCone: - SetSubComponentModeAngleCone(config); - break; - case EditorSubComponentModeType::Vec3: - SetSubComponentModeVec3(config); - break; - case EditorSubComponentModeType::Rotation: - SetSubComponentModeRotation(config); - break; - case EditorSubComponentModeType::SnapPosition: - SetSubComponentModeSnapPosition(config); - break; - case EditorSubComponentModeType::SnapRotation: - SetSubComponentModeSnapRotation(config); - break; - default: - AZ_Error("EditorJointComponentMode::SetCurrentSubComponentMode" - , false - , "Unsupported sub-component mode type."); - } - } - - bool EditorJointComponentMode::IsSubComponentModeUsed(const AZStd::string& subComponentModeName) - { - bool isUsed = false; - EditorJointRequestBus::EventResult( - isUsed, m_entityComponentIdPair - , &EditorJointRequests::IsParameterUsed - , subComponentModeName); - return isUsed; - } - - void EditorJointComponentMode::SetSubComponentModeAngleCone(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name - , config.m_max - , config.m_min); - } - - void EditorJointComponentMode::SetSubComponentModeAnglePair(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name - , config.m_axis - , config.m_max - , config.m_min - , config.m_min - , -config.m_max); - } - - void EditorJointComponentMode::SetSubComponentModeLinear(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name - , config.m_exponent - , config.m_max - , config.m_min); - } - - void EditorJointComponentMode::SetSubComponentModeVec3(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name); - } - - void EditorJointComponentMode::SetSubComponentModeRotation(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name); - } - - void EditorJointComponentMode::SetSubComponentModeSnapPosition(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name - , config.m_selectLeadOnSnap); - } - - void EditorJointComponentMode::SetSubComponentModeSnapRotation(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name); - } - - EditorBallJointComponentMode::EditorBallJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) - : EditorJointComponentMode(entityComponentIdPair, componentType) - { - m_configMap = Configure(); - NextMode(); - } - - EditorBallJointComponentMode::~EditorBallJointComponentMode() - { - if (m_currentSubComponentMode) - { - m_currentSubComponentMode.reset(); - } - } - - void EditorJointComponentMode::Refresh() - { - if (m_currentSubComponentMode) - { - m_currentSubComponentMode->Refresh(); - } - } - - AZStd::map EditorBallJointComponentMode::Configure() - { - AZStd::map configMap; - - configMap.emplace( - EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeType::Vec3) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeType::Rotation) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterSnapPosition - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSnapPosition - , EditorSubComponentModeType::SnapPosition) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterSnapRotation - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSnapRotation - , EditorSubComponentModeType::SnapRotation) - ); - - const float exponentBreakage = 1.0f; - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - const float exponentSpring = 2.0f; - - configMap.emplace( - EditorJointComponentMode::s_parameterDamping - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterDamping - , EditorSubComponentModeType::Linear - , exponentSpring - , PhysX::EditorJointLimitConeConfig::s_springMax - , PhysX::EditorJointLimitConeConfig::s_springMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterStiffness - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterStiffness - , EditorSubComponentModeType::Linear - , exponentSpring - , PhysX::EditorJointLimitConeConfig::s_springMax - , PhysX::EditorJointLimitConeConfig::s_springMin) - ); - - // Cone tip to base is always X-axis. - //The angle cone defines the limitations for rotation about the Y and Z axes. - configMap.emplace( - EditorJointComponentMode::s_parameterSwingLimit - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSwingLimit - , EditorSubComponentModeType::AngleCone - , PhysX::EditorJointLimitConeConfig::s_angleMax - , PhysX::EditorJointLimitConeConfig::s_angleMin) - ); - - return configMap; - } - - EditorFixedJointComponentMode::EditorFixedJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) - : EditorJointComponentMode(entityComponentIdPair, componentType) - { - m_configMap = Configure(); - NextMode(); - } - - EditorFixedJointComponentMode::~EditorFixedJointComponentMode() - { - if (m_currentSubComponentMode) - { - m_currentSubComponentMode.reset(); - } - } - - AZStd::map EditorFixedJointComponentMode::Configure() - { - AZStd::map configMap; - - configMap.emplace( - EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeType::Vec3) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeType::Rotation) - ); - - const float exponentBreakage = 1.0f; - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - return configMap; - } - - EditorHingeJointComponentMode::EditorHingeJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) - : EditorJointComponentMode(entityComponentIdPair, componentType) - { - m_configMap = Configure(); - NextMode(); - } - - EditorHingeJointComponentMode::~EditorHingeJointComponentMode() - { - if (m_currentSubComponentMode) - { - m_currentSubComponentMode.reset(); - } - } - - AZStd::map EditorHingeJointComponentMode::Configure() - { - AZStd::map configMap; - - configMap.emplace( - EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeType::Vec3) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeType::Rotation) - ); - - const float exponentBreakage = 1.0f; - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - const float exponentSpring = 2.0f; - - configMap.emplace( - EditorJointComponentMode::s_parameterDamping - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterDamping - , EditorSubComponentModeType::Linear - , exponentSpring - , PhysX::EditorJointLimitPairConfig::s_springMax - , PhysX::EditorJointLimitPairConfig::s_springMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterStiffness - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterStiffness - , EditorSubComponentModeType::Linear - , exponentSpring - , PhysX::EditorJointLimitPairConfig::s_springMax - , PhysX::EditorJointLimitPairConfig::s_springMin) - ); - - AZ::Vector3 axis = AZ::Vector3::CreateAxisX(); // PhysX revolute joints uses the x-axis by default - configMap.emplace( - EditorJointComponentMode::s_parameterAngularPair - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterAngularPair - , EditorSubComponentModeType::AnglePair - , axis - , PhysX::EditorJointLimitPairConfig::s_angleMax - , PhysX::EditorJointLimitPairConfig::s_angleMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterSnapPosition - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSnapPosition - , EditorSubComponentModeType::SnapPosition) - ); - - return configMap; - } -} // namespace LmbrCentral diff --git a/Gems/PhysX/Code/Editor/EditorJointComponentMode.h b/Gems/PhysX/Code/Editor/EditorJointComponentMode.h deleted file mode 100644 index 023edcc24b..0000000000 --- a/Gems/PhysX/Code/Editor/EditorJointComponentMode.h +++ /dev/null @@ -1,173 +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 - -namespace PhysX -{ - enum class EditorSubComponentModeType : AZ::u8 - { - Linear, /// sub-component mode to modify a single linear value, e.g. a float value. - AnglePair, /// sub-component mode to modify a pair of float values representing angles. - AngleCone, /// sub-component mode to modify a constraint's swing limits and local transformation. - Rotation, /// sub-component mode to modify local transformation. - SnapPosition, /// sub-component mode to modify local position using a point-and-snap feature in the viewport. - SnapRotation, /// sub-component mode to modify local rotation using a point-and-snap feature in the viewport. - Vec3 /// sub-component mode to modify a Vector3 value. - }; - - /// Contains configuration of a sub-component mode. Shared by different types of sub-component mode. - /// Alternative implementation of this struct using AZStd::Variant is pending the development of the rest of the joint types. - struct EditorSubComponentModeConfig - { - EditorSubComponentModeConfig() = default; - - EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type); - - EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , float exponent - , float max - , float min); - - EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , const AZ::Vector3& axis - , float max - , float min); - - EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , float max - , float min); - - AZStd::string m_name; - EditorSubComponentModeType m_type; - AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); - float m_exponent = 1.0f; - float m_max = FLT_MAX; - float m_min = -FLT_MAX; - bool m_selectLeadOnSnap = true; ///< A user may use the snap-to-position component mode to snap the position of a joint to an entity. This flag indicates if the snapped-to entity would be selected as a joint's lead when that happens. - }; - - /// Generic component mode that supports multiple sub-component modes. - class EditorJointComponentMode - : public AzToolsFramework::ComponentModeFramework::EditorBaseComponentMode - { - public: - static const AZStd::string s_parameterAngularPair; - static const AZStd::string s_parameterDamping; - static const AZStd::string s_parameterMaxForce; - static const AZStd::string s_parameterMaxTorque; - static const AZStd::string s_parameterPosition; - static const AZStd::string s_parameterRotation; - static const AZStd::string s_parameterSnapPosition; - static const AZStd::string s_parameterSnapRotation; - static const AZStd::string s_parameterStiffness; - static const AZStd::string s_parameterSwingLimit; - static const AZStd::string s_parameterTolerance; - static const AZStd::string s_parameterTransform; - static const AZStd::string s_parameterComponentMode; - static const AZStd::string s_parameterLeadEntity; - static const AZStd::string s_parameterSelectOnSnap; - - EditorJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType); - ~EditorJointComponentMode(); - - // EditorBaseComponentMode - void Refresh() override; - - /// Returns map of sub-component mode configurations required by this component mode. - virtual AZStd::map Configure() = 0; - - protected: - /// AzToolsFramework::ViewportInteraction::MouseViewportRequests - bool HandleMouseInteraction( - const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; - - /// EditorBaseComponentMode - AZStd::vector PopulateActionsImpl() override; - - /// Changes to the next sub-component mode found in m_configMap. - void NextMode(); - - /// Changes to the previous sub-component mode found in m_configMap. - void PreviousMode(); - - /// Changes to the next or previous sub-component mode found in m_configMap. - void ChangeMode(bool forwardChange); - - /// Replaces m_currentSubComponentMode with a new one instantiated using the configuration identified by the input subComponentModeName. - void SetCurrentSubComponentMode(const AZStd::string& subComponentModeName); - - AZStd::shared_ptr m_currentSubComponentMode = nullptr; ///< The active sub-component mode in this component mode. - AZ::Uuid m_componentType = AZ::Uuid::CreateNull(); - AZStd::map m_configMap; ///< Contains sub-component mode configurations supported by this component mode. - AZ::EntityComponentIdPair m_entityComponentIdPair; - - private: - bool IsSubComponentModeUsed(const AZStd::string& subComponentModeName); - - void SetSubComponentModeAngleCone(const EditorSubComponentModeConfig& config); - void SetSubComponentModeAnglePair(const EditorSubComponentModeConfig& config); - void SetSubComponentModeLinear(const EditorSubComponentModeConfig& config); - void SetSubComponentModeVec3(const EditorSubComponentModeConfig& config); - void SetSubComponentModeRotation(const EditorSubComponentModeConfig& config); - void SetSubComponentModeSnapPosition(const EditorSubComponentModeConfig& config); - void SetSubComponentModeSnapRotation(const EditorSubComponentModeConfig& config); - }; - - /// Ball joint specific component mode. Configure() is overriden to set up the required sub-component modes. - class EditorBallJointComponentMode - : public EditorJointComponentMode - { - public: - EditorBallJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType); - ~EditorBallJointComponentMode(); - - // EditorJointComponentMode - AZStd::map Configure() override; - }; - - /// Fixed joint specific component mode. Configure() is overriden to set up the required sub-component modes. - class EditorFixedJointComponentMode - : public EditorJointComponentMode - { - public: - EditorFixedJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType); - ~EditorFixedJointComponentMode(); - - // EditorJointComponentMode - AZStd::map Configure() override; - }; - - /// Hinge joint specific component mode. Configure() is overriden to set up the required sub-component modes. - class EditorHingeJointComponentMode - : public EditorJointComponentMode - { - public: - EditorHingeJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType); - ~EditorHingeJointComponentMode(); - - // EditorJointComponentMode - AZStd::map Configure() override; - }; - - using ConfigMap = AZStd::map; - using ConfigMapIter = ConfigMap::iterator; - using ConfigMapReverseIter = ConfigMap::reverse_iterator; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.cpp b/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.cpp deleted file mode 100644 index 53b27f6cde..0000000000 --- a/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.cpp +++ /dev/null @@ -1,68 +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 - -namespace PhysX -{ - EditorJointTypeDrawer::EditorJointTypeDrawer(EditorJointType jointType, - AzFramework::EntityContextId entityContextId, - const AZStd::string& subComponentModeName): - m_subComponentModeName(subComponentModeName) - { - AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(entityContextId); - EditorJointTypeDrawerBus::Handler::BusConnect(EditorJointTypeDrawerId(jointType, - EditorSubComponentModeNameCrc(subComponentModeName))); - } - - EditorJointTypeDrawer::~EditorJointTypeDrawer() - { - EditorJointTypeDrawerBus::Handler::BusDisconnect(); - AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect(); - } - - void EditorJointTypeDrawer::DisplayViewport2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) - { - const AZ::u32 stateBefore = debugDisplay.GetState(); - - const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId); - - const float xOffsetCurrentMode = 125.0f; - const float yOffsetCurrentMode = 55.0f; - - const float xOffsetHotKeys = 125.0f; - const float yOffsetHotKeys = 30.0f; - - const float viewportWidthHalf = cameraState.m_viewportSize.GetX() / 2.0f; - const float viewportHeight = cameraState.m_viewportSize.GetY(); - - debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, 1.0f)); - - AZStd::string screenTextCurrentMode = "Edit mode: " + m_subComponentModeName; - float xPos = viewportWidthHalf - xOffsetCurrentMode; - float yPos = viewportHeight - yOffsetCurrentMode; - float textSize = 2.0f; - debugDisplay.Draw2dTextLabel(xPos, yPos, textSize, screenTextCurrentMode.c_str()); - - AZStd::string screenTextHotKeys = " or to change modes"; - xPos = viewportWidthHalf - xOffsetHotKeys; - yPos = viewportHeight - yOffsetHotKeys; - textSize = 1.2f; - debugDisplay.Draw2dTextLabel(xPos, yPos, textSize, screenTextHotKeys.c_str()); - - debugDisplay.SetState(stateBefore); - } - - AZStd::shared_ptr EditorJointTypeDrawer::GetEditorJointTypeDrawer() - { - return shared_from_this(); - } - -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.h b/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.h deleted file mode 100644 index 4172424f00..0000000000 --- a/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.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 -#include -#include - -namespace PhysX -{ - /// This class enables drawing in the viewport once for the component modes of multiple components in one entity. - /// Until the component mode framework allows a way to do this, a work-around like this class is necessary. - /// An instance of this class is created for each pair of component type and sub-component mode. - class EditorJointTypeDrawer - : public EditorJointTypeDrawerBus::Handler - , public AZStd::enable_shared_from_this - , private AzFramework::ViewportDebugDisplayEventBus::Handler - { - public: - EditorJointTypeDrawer(EditorJointType id, - AzFramework::EntityContextId entityContextId, - const AZStd::string& subComponentModeName); - ~EditorJointTypeDrawer(); - - private: - // AzFramework::ViewportDebugDisplayEventBus - void DisplayViewport2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; - - // PhysX::EditorJointTypeDrawerBus - AZStd::shared_ptr GetEditorJointTypeDrawer() override; - - AZStd::string m_subComponentModeName;///< Name of the sub component mode. E.g. Position, Rotation, Snap Position, etc. - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorJointTypeDrawerBus.h b/Gems/PhysX/Code/Editor/EditorJointTypeDrawerBus.h deleted file mode 100644 index e47c447fe2..0000000000 --- a/Gems/PhysX/Code/Editor/EditorJointTypeDrawerBus.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 - -#include - -namespace PhysX -{ - class EditorJointTypeDrawer; - - using EditorJointType = AZ::Uuid; - using EditorSubComponentModeNameCrc = AZ::Crc32; - using EditorJointTypeDrawerId = AZStd::pair; - - /// The sub-component mode of a component type uses this bus (by invoking GetEditorJointTypeDrawer) to retrieve a drawer. - /// If nothing is returned, it creates an instance of the drawer that will be shared by other instances of the same component type. - class EditorJointTypeDrawerRequests : public AZ::EBusTraits - { - public: - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - using BusIdType = EditorJointTypeDrawerId; - - virtual AZStd::shared_ptr GetEditorJointTypeDrawer() = 0; - }; - using EditorJointTypeDrawerBus = AZ::EBus; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.cpp deleted file mode 100644 index 43b9fd77f3..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.cpp +++ /dev/null @@ -1,453 +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 - -namespace -{ - const float ArrowLength = 2.0f; - const float ConeHeight = 3.0f; - const float XRotationManipulatorRadius = 2.0f; - const float XRotationManipulatorWidth = 0.05f; -} - -namespace PhysX -{ - struct SharedRotationState - { - AZ::Vector3 m_axis; - AZ::Quaternion m_savedOrientation = AZ::Quaternion::CreateIdentity(); - AngleLimitsFloatPair m_valuePair; - }; - - EditorSubComponentModeAngleCone::EditorSubComponentModeAngleCone( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , float max - , float min) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) - , m_max(max) - , m_min(min) - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - const AZ::Quaternion localRotation = localTransform.GetRotation(); - - // Initialize manipulators used to resize the base of the cone. - m_yLinearManipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); - m_yLinearManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_yLinearManipulator->SetAxis(AZ::Vector3::CreateAxisZ()); - - m_zLinearManipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); - m_zLinearManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_zLinearManipulator->SetAxis(AZ::Vector3::CreateAxisY()); - - m_yzPlanarManipulator = AzToolsFramework::PlanarManipulator::MakeShared(worldTransform); - m_yzPlanarManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_yzPlanarManipulator->SetAxes(AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); - - ConfigureLinearView(ArrowLength - , AZ::Color(1.0f, 0.0f, 0.0f, 1.0f) - , AZ::Color(0.0f, 1.0f, 0.0f, 1.0f) - , AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)); - - ConfigurePlanarView(AZ::Color(0.0f, 1.0f, 0.0f, 1.0f) - , AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)); - - // Position and orientate manipulators - AZ::Transform displacementTransform = localTransform; - AZ::Vector3 displacementTranslate = localRotation.TransformVector(AZ::Vector3(ConeHeight, 0.0f, 0.0f)); - displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); - - m_yLinearManipulator->SetLocalTransform(displacementTransform); - m_zLinearManipulator->SetLocalTransform(displacementTransform); - m_yzPlanarManipulator->SetLocalTransform(displacementTransform); - - // Initialize rotation manipulator for rotating cone - m_xRotationManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); - m_xRotationManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_xRotationManipulator->SetAxis(AZ::Vector3::CreateAxisX()); - m_xRotationManipulator->SetLocalTransform(localTransform); - - const AZ::Color xRotationManipulatorColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f); - m_xRotationManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( - *m_xRotationManipulator, xRotationManipulatorColor, - XRotationManipulatorRadius, XRotationManipulatorWidth, AzToolsFramework::DrawHalfDottedCircle)); - - AZStd::shared_ptr sharedRotationState = - AZStd::make_shared(); - - struct SharedState - { - AngleLimitsFloatPair m_startValues; - }; - auto sharedState = AZStd::make_shared(); - - m_yLinearManipulator->InstallLeftMouseDownCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable - { - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - sharedState->m_startValues = currentValue; - }); - - m_yLinearManipulator->InstallMouseMoveCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - const AZ::Quaternion localRotation = localTransform.GetRotation(); - const float axisDisplacement = action.LocalPositionOffset().Dot(localRotation.TransformVector(action.m_fixed.m_axis)); - const float originalBaseY = tan(AZ::DegToRad(sharedState->m_startValues.first)) * ConeHeight; - const float newBaseY = originalBaseY + axisDisplacement; - const float newAngle = AZ::GetClamp(AZ::RadToDeg(atan(newBaseY / ConeHeight)), m_min, m_max); - - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValuePair - , m_name - , AngleLimitsFloatPair(newAngle, sharedState->m_startValues.second)); - - m_yLinearManipulator->SetBoundsDirty(); - }); - - m_zLinearManipulator->InstallLeftMouseDownCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable - { - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - sharedState->m_startValues = currentValue; - }); - - m_zLinearManipulator->InstallMouseMoveCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - const AZ::Quaternion localRotation = localTransform.GetRotation(); - const float axisDisplacement = action.LocalPositionOffset().Dot(localRotation.TransformVector(action.m_fixed.m_axis)); - const float originalBaseZ = tan(AZ::DegToRad(sharedState->m_startValues.second)) * ConeHeight; - const float newBaseZ = originalBaseZ + axisDisplacement; - const float newAngle = AZ::GetClamp(AZ::RadToDeg(atan(newBaseZ / ConeHeight)), m_min, m_max); - - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValuePair - , m_name - , AngleLimitsFloatPair(sharedState->m_startValues.first, newAngle)); - - m_zLinearManipulator->SetBoundsDirty(); - }); - - m_yzPlanarManipulator->InstallLeftMouseDownCallback( - [this, sharedState](const AzToolsFramework::PlanarManipulator::Action& /*action*/) mutable - { - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - sharedState->m_startValues = currentValue; - }); - - m_yzPlanarManipulator->InstallMouseMoveCallback( - [this, sharedState](const AzToolsFramework::PlanarManipulator::Action& action) - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - const AZ::Quaternion localRotation = localTransform.GetRotation(); - - const float axisDisplacementY = action.LocalPositionOffset().Dot(localRotation.TransformVector(AZ::Vector3::CreateAxisY())); - const float axisDisplacementZ = action.LocalPositionOffset().Dot(localRotation.TransformVector(AZ::Vector3::CreateAxisZ())); - const float axisDisplacement = axisDisplacementZ > axisDisplacementY? axisDisplacementZ : axisDisplacementY; - - const float originalBaseY = tan(AZ::DegToRad(sharedState->m_startValues.first)) * ConeHeight; - const float newBaseY = originalBaseY + axisDisplacement; - const float newAngleY = AZ::GetClamp(AZ::RadToDeg(atan(newBaseY / ConeHeight)), m_min, m_max); - - const float originalBaseZ = tan(AZ::DegToRad(sharedState->m_startValues.second)) * ConeHeight; - const float newBaseZ = originalBaseZ + axisDisplacement; - const float newAngleZ = AZ::GetClamp(AZ::RadToDeg(atan(newBaseZ / ConeHeight)), m_min, m_max); - - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValuePair - , m_name - , AngleLimitsFloatPair(newAngleY, newAngleZ)); - - m_yzPlanarManipulator->SetBoundsDirty(); - }); - - struct SharedStateXRotate - { - AZ::Transform m_startTM; - }; - auto sharedStateXRotate = AZStd::make_shared(); - - auto mouseDownCallback = [this, sharedRotationState](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - AZ::Quaternion normalizedStart = action.m_start.m_rotation.GetNormalized(); - sharedRotationState->m_axis = AZ::Vector3(normalizedStart.GetX(), normalizedStart.GetY(), normalizedStart.GetZ()); - sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); - - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - - sharedRotationState->m_valuePair = currentValue; - }; - - auto mouseDownRotateXCallback = [this, sharedStateXRotate]([[maybe_unused]] const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - PhysX::EditorJointRequestBus::EventResult(sharedStateXRotate->m_startTM - , m_entityComponentId - , &PhysX::EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - }; - - m_xRotationManipulator->InstallLeftMouseDownCallback(mouseDownRotateXCallback); - - m_xRotationManipulator->InstallMouseMoveCallback( - [this, sharedStateXRotate] - (const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; - - AZ::Transform newTransform = AZ::Transform::CreateIdentity(); - newTransform = sharedStateXRotate->m_startTM * AZ::Transform::CreateFromQuaternion(action.m_current.m_delta); - - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetVector3Value - , PhysX::EditorJointComponentMode::s_parameterPosition - , newTransform.GetTranslation()); - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetVector3Value - , PhysX::EditorJointComponentMode::s_parameterRotation - , newTransform.GetRotation().GetEulerDegrees()); - - m_yLinearManipulator->SetLocalOrientation(manipulatorOrientation); - m_zLinearManipulator->SetLocalOrientation(manipulatorOrientation); - m_yLinearManipulator->SetAxis(action.m_current.m_delta.TransformVector(AZ::Vector3::CreateAxisY())); - m_zLinearManipulator->SetAxis(action.m_current.m_delta.TransformVector(AZ::Vector3::CreateAxisZ())); - m_xRotationManipulator->SetLocalOrientation(manipulatorOrientation); - - m_yLinearManipulator->SetBoundsDirty(); - m_zLinearManipulator->SetBoundsDirty(); - m_xRotationManipulator->SetBoundsDirty(); - }); - - m_xRotationManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - m_yLinearManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - m_zLinearManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - m_yzPlanarManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - - AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); - - Refresh(); - } - - EditorSubComponentModeAngleCone::~EditorSubComponentModeAngleCone() - { - AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); - - m_xRotationManipulator->Unregister(); - m_yLinearManipulator->Unregister(); - m_zLinearManipulator->Unregister(); - m_yzPlanarManipulator->Unregister(); - } - - void EditorSubComponentModeAngleCone::Refresh() - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - float coneHeight = ConeHeight; - AngleLimitsFloatPair yzSwingAngleLimits; - EditorJointRequestBus::EventResult( - yzSwingAngleLimits, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - - // Draw inverted cone (negative cone height) if angles are larger than 90 deg. - if (yzSwingAngleLimits.first > 90.0f || yzSwingAngleLimits.second > 90.0f) - { - coneHeight = -ConeHeight; - } - - // reposition manipulators - const AZ::Quaternion localRotation = localTransform.GetRotation(); - const AZ::Vector3 linearManipulatorOffset = localTransform.GetTranslation() + localRotation.TransformVector(AZ::Vector3(coneHeight, 0.0f, 0.0f)); - - m_xRotationManipulator->SetLocalTransform(localTransform); - m_xRotationManipulator->SetBoundsDirty(); - - localTransform.SetTranslation(linearManipulatorOffset); - - m_yLinearManipulator->SetLocalTransform(localTransform); - m_zLinearManipulator->SetLocalTransform(localTransform); - m_yzPlanarManipulator->SetLocalTransform(localTransform); - m_yLinearManipulator->SetBoundsDirty(); - m_zLinearManipulator->SetBoundsDirty(); - m_yzPlanarManipulator->SetBoundsDirty(); - } - - void EditorSubComponentModeAngleCone::ConfigureLinearView( - float axisLength, [[maybe_unused]] const AZ::Color& axis1Color, const AZ::Color& axis2Color, - const AZ::Color& axis3Color) - { - const float coneLength = 0.28f; - const float coneRadius = 0.07f; - - const auto configureLinearView = [coneLength, axisLength, coneRadius]( - AzToolsFramework::LinearManipulator* linearManipulator, const AZ::Color& color) - { - AzToolsFramework::ManipulatorViews views; - views.emplace_back(CreateManipulatorViewLine( - *linearManipulator, color, axisLength, AzToolsFramework::ManipulatorLineBoundWidth())); - views.emplace_back(CreateManipulatorViewCone( - *linearManipulator, color, linearManipulator->GetAxis() * (axisLength - coneLength), - coneLength, coneRadius)); - linearManipulator->SetViews(AZStd::move(views)); - }; - - configureLinearView(m_yLinearManipulator.get(), axis2Color); - configureLinearView(m_zLinearManipulator.get(), axis3Color); - } - - void EditorSubComponentModeAngleCone::ConfigurePlanarView(const AZ::Color& planeColor, - const AZ::Color& plane2Color) - { - const float planeSize = 0.6f; - AzToolsFramework::ManipulatorViews views; - views.emplace_back(CreateManipulatorViewQuad( - *m_yzPlanarManipulator - , planeColor - , plane2Color - , planeSize)); - m_yzPlanarManipulator->SetViews(AZStd::move(views)); - } - - void EditorSubComponentModeAngleCone::DisplayEntityViewport( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - AZ::u32 stateBefore = debugDisplay.GetState(); - debugDisplay.CullOff(); - - debugDisplay.PushMatrix(worldTransform); - debugDisplay.PushMatrix(localTransform); - - const float xAxisArrowLength = 2.0f; - debugDisplay.SetColor(AZ::Color(1.0f, 0.0f, 0.0f, 1.0f)); - debugDisplay.DrawArrow(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(xAxisArrowLength, 0.0f, 0.0f)); - - AngleLimitsFloatPair yzSwingAngleLimits; - EditorJointRequestBus::EventResult( - yzSwingAngleLimits, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - - const AZ::u32 numEllipseSamples = 16; - AZ::Vector3 ellipseSamples[numEllipseSamples]; - float coneHeight = ConeHeight; - - // Draw inverted cone if angles are larger than 90 deg. - if (yzSwingAngleLimits.first > 90.0f || yzSwingAngleLimits.second > 90.0f) - { - coneHeight = -ConeHeight; - } - - // Compute points along perimeter of cone base - const float coney = tanf(AZ::DegToRad(yzSwingAngleLimits.first)) * coneHeight; - const float conez = tanf(AZ::DegToRad(yzSwingAngleLimits.second)) * coneHeight; - const float step = AZ::Constants::TwoPi / numEllipseSamples; - for (size_t i = 0; i < numEllipseSamples; ++i) - { - const float angleStep = step * i; - ellipseSamples[i].SetX(coneHeight); - ellipseSamples[i].SetY(conez * sin(angleStep)); - ellipseSamples[i].SetZ(coney * cos(angleStep)); - } - - // draw cone - for (size_t i = 0; i < numEllipseSamples; ++i) - { - size_t nextIndex = i + 1; - if (i == numEllipseSamples - 1) - { - nextIndex = 0; - } - - // draw cone sides - debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, 0.2f)); - debugDisplay.DrawTri(AZ::Vector3(0.0f, 0.0f, 0.0f), ellipseSamples[i], ellipseSamples[nextIndex]); - - // draw parameter of cone base - debugDisplay.SetColor(AZ::Color(0.4f, 0.4f, 0.4f, 0.4f)); - debugDisplay.DrawLine(ellipseSamples[i], ellipseSamples[nextIndex]); - } - - // draw axis lines at base of cone, and from tip to base. - debugDisplay.SetColor(AZ::Color(0.5f, 0.5f, 0.5f, 0.6f)); - debugDisplay.DrawLine(ellipseSamples[0], ellipseSamples[numEllipseSamples/2]); - debugDisplay.DrawLine(ellipseSamples[numEllipseSamples*3/4], ellipseSamples[numEllipseSamples/4]); - debugDisplay.DrawLine(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(coneHeight, 0.0f, 0.0f)); - - debugDisplay.PopMatrix();//pop local transform - debugDisplay.PopMatrix();//pop world transform - debugDisplay.SetState(stateBefore); - - // reposition and reorientate manipulators - Refresh(); - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.h deleted file mode 100644 index bf113b4be1..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.h +++ /dev/null @@ -1,63 +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 - -namespace AzToolsFramework -{ - class AngularManipulator; - class LinearManipulator; - class PlanarManipulator; -} - -namespace PhysX -{ - class EditorSubComponentModeAngleCone - : public PhysX::EditorSubComponentModeBase - , private AzFramework::EntityDebugDisplayEventBus::Handler - { - public: - EditorSubComponentModeAngleCone( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , float max - , float min); - ~EditorSubComponentModeAngleCone(); - - // PhysX::EditorSubComponentModeBase - void Refresh() override; - - private: - // AzFramework::EntityDebugDisplayEventBus - void DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; - - void ConfigureLinearView( - float axisLength, - const AZ::Color& axis1Color, const AZ::Color& axis2Color, - const AZ::Color& axis3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); - - void ConfigurePlanarView(const AZ::Color& planeColor = AZ::Color(0.0f, 1.0f, 0.0f, 0.5f) - , const AZ::Color& plane2Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); - - AZStd::shared_ptr m_xRotationManipulator; - AZStd::shared_ptr m_yLinearManipulator; - AZStd::shared_ptr m_zLinearManipulator; - AZStd::shared_ptr m_yzPlanarManipulator; - - float m_max = FLT_MAX; - float m_min = 0.0f; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.cpp deleted file mode 100644 index 6fa74a3f05..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.cpp +++ /dev/null @@ -1,318 +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 -{ - const float Alpha = 0.6f; - const AZ::Color ColorDefault = AZ::Color(1.0f, 1.0f, 1.0f, Alpha); - const AZ::Color ColorFirst = AZ::Color(1.0f, 0.0f, 0.0f, Alpha); - const AZ::Color ColorSecond = AZ::Color(0.0f, 1.0f, 0.0f, Alpha); - const AZ::Color ColorSweepArc = AZ::Color(1.0f, 1.0f, 1.0f, Alpha); - - const float SweepLineDisplaceFactor = 0.5f; - const float SweepLineThickness = 1.0f; - const float SweepLineGranularity = 1.0f; -} - -namespace PhysX -{ - EditorSubComponentModeAnglePair::EditorSubComponentModeAnglePair( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , const AZ::Vector3& axis - , float firstMax - , float firstMin - , float secondMax - , float secondMin) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) - , m_axis(axis) - , m_firstMax(firstMax) - , m_firstMin(firstMin) - , m_secondMax(secondMax) - , m_secondMin(secondMin) - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - const AZ::Quaternion localRotation = localTransform.GetRotation(); - - AZ::Vector3 displacement = m_axis; - AZ::Transform displacementTransform = localTransform; - AZ::Vector3 displacementTranslate = localRotation.TransformVector(displacement); - displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); - - m_firstManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); - m_firstManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_firstManipulator->SetAxis(m_axis); - m_firstManipulator->SetLocalTransform(displacementTransform); - - displacement = -m_axis; - displacementTranslate = localRotation.TransformVector(displacement); - displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); - m_secondManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); - m_secondManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_secondManipulator->SetAxis(m_axis); - m_secondManipulator->SetLocalTransform(displacementTransform); - - const float manipulatorRadius = 2.0f; - const float manipulatorWidth = 0.05f; - m_firstManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( - *m_firstManipulator, ColorFirst, - manipulatorRadius, manipulatorWidth, AzToolsFramework::DrawHalfDottedCircle)); - - m_secondManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( - *m_secondManipulator, ColorSecond, - manipulatorRadius, manipulatorWidth, AzToolsFramework::DrawHalfDottedCircle)); - - Refresh(); - - AZStd::shared_ptr sharedRotationState = - AZStd::make_shared(); - - auto mouseDownCallback = [this, sharedRotationState](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - const AZ::Quaternion normalizedStart = action.m_start.m_rotation.GetNormalized(); - sharedRotationState->m_axis = AZ::Vector3(normalizedStart.GetX(), normalizedStart.GetY(), normalizedStart.GetZ()); - sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); - - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - - sharedRotationState->m_valuePair = currentValue; - }; - - m_firstManipulator->InstallLeftMouseDownCallback(mouseDownCallback); - - m_secondManipulator->InstallLeftMouseDownCallback(mouseDownCallback); - - m_firstManipulator->InstallMouseMoveCallback( - [this, sharedRotationState] - (const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - float angleDelta; - AZ::Quaternion manipulatorOrientation; - const float newValue = MouseMove(sharedRotationState, action, true, angleDelta, manipulatorOrientation); - if (newValue > m_firstMax || newValue < m_firstMin) - { - return; - } - m_firstManipulator->SetLocalOrientation(manipulatorOrientation); - const float newFirstValue = AZ::GetClamp(sharedRotationState->m_valuePair.first + angleDelta, m_firstMin, m_firstMax); - - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValuePair - , m_name - , AngleLimitsFloatPair(newFirstValue, sharedRotationState->m_valuePair.second)); - - m_firstManipulator->SetBoundsDirty(); - }); - - m_secondManipulator->InstallMouseMoveCallback( - [this, sharedRotationState] - (const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - float angleDelta; - AZ::Quaternion manipulatorOrientation; - const float newValue = MouseMove(sharedRotationState, action, false, angleDelta, manipulatorOrientation); - if (newValue > m_secondMax || newValue < m_secondMin) - { - return; //Not handling values exceeding limits - } - - m_secondManipulator->SetLocalOrientation(manipulatorOrientation); - float newSecondValue = AZ::GetClamp(sharedRotationState->m_valuePair.second + angleDelta, m_secondMin, m_secondMax); - - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValuePair - , m_name - , AngleLimitsFloatPair(sharedRotationState->m_valuePair.first, newSecondValue)); - - m_secondManipulator->SetBoundsDirty(); - }); - - - m_firstManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - m_secondManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - - AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); - } - - EditorSubComponentModeAnglePair::~EditorSubComponentModeAnglePair() - { - AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); - - m_firstManipulator->Unregister(); - m_secondManipulator->Unregister(); - } - - void EditorSubComponentModeAnglePair::Refresh() - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - const AZ::Quaternion localRotation = localTransform.GetRotation(); - - AZ::Transform displacementTransform = localTransform; - AZ::Vector3 displacement = m_axis; - AZ::Vector3 displacementTranslate = localRotation.TransformVector(displacement); - displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); - m_firstManipulator->SetLocalTransform(displacementTransform); - - displacement = -m_axis; - displacementTranslate = localRotation.TransformVector(displacement); - displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); - m_secondManipulator->SetLocalTransform(displacementTransform); - - m_firstManipulator->SetBoundsDirty(); - m_secondManipulator->SetBoundsDirty(); - } - - void EditorSubComponentModeAnglePair::DisplayEntityViewport( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) - { - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - - const float size = 2.0f; - AZ::Vector3 axisPoint = m_axis * size * 0.5f; - - AZStd::array points = { - -axisPoint - , axisPoint - , axisPoint - , -axisPoint - }; - - if (abs(m_axis.GetX() - 1.0f) < FLT_EPSILON) - { - points[2].SetZ(size); - points[3].SetZ(size); - } - else if (abs(m_axis.GetY() - 1.0f) < FLT_EPSILON) - { - points[2].SetX(size); - points[3].SetX(size); - } - else if (abs(m_axis.GetZ() - 1.0f) < FLT_EPSILON) - { - points[2].SetX(size); - points[3].SetX(size); - } - - AZ::u32 stateBefore = debugDisplay.GetState(); - debugDisplay.CullOff(); - debugDisplay.SetAlpha(Alpha); - - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - debugDisplay.PushMatrix(worldTransform); - debugDisplay.PushMatrix(localTransform); - - debugDisplay.SetColor(ColorSweepArc); - - const AZ::Vector3 zeroVector = AZ::Vector3::CreateZero(); - const AZ::Vector3 posPosition = m_axis * SweepLineDisplaceFactor; - const AZ::Vector3 negPosition = -posPosition; - debugDisplay.DrawArc(posPosition, SweepLineThickness, -currentValue.first, currentValue.first, SweepLineGranularity, -m_axis); - debugDisplay.DrawArc(zeroVector, SweepLineThickness, -currentValue.first, currentValue.first, SweepLineGranularity, -m_axis); - debugDisplay.DrawArc(negPosition, SweepLineThickness, -currentValue.first, currentValue.first, SweepLineGranularity, -m_axis); - debugDisplay.DrawArc(posPosition, SweepLineThickness, 0.0f, abs(currentValue.second), SweepLineGranularity, -m_axis); - debugDisplay.DrawArc(zeroVector, SweepLineThickness, 0.0f, abs(currentValue.second), SweepLineGranularity, -m_axis); - debugDisplay.DrawArc(negPosition, SweepLineThickness, 0.0f, abs(currentValue.second), SweepLineGranularity, -m_axis); - - AZ::Quaternion firstRotate = AZ::Quaternion::CreateFromAxisAngle(m_axis, AZ::DegToRad(currentValue.first)); - AZ::Transform firstTM = AZ::Transform::CreateFromQuaternion(firstRotate); - debugDisplay.PushMatrix(firstTM); - debugDisplay.SetColor(ColorFirst); - debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); - debugDisplay.PopMatrix(); - - AZ::Quaternion secondRotate = AZ::Quaternion::CreateFromAxisAngle(m_axis, AZ::DegToRad(currentValue.second)); - AZ::Transform secondTM = AZ::Transform::CreateFromQuaternion(secondRotate); - debugDisplay.PushMatrix(secondTM); - debugDisplay.SetColor(ColorSecond); - debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); - debugDisplay.PopMatrix(); - - debugDisplay.SetColor(ColorDefault); - debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); - - debugDisplay.PopMatrix(); // pop local transform - debugDisplay.PopMatrix(); // pop global transform - debugDisplay.SetState(stateBefore); - - // reposition and reorientate manipulators - Refresh(); - } - - float EditorSubComponentModeAnglePair::MouseMove(AZStd::shared_ptr& sharedRotationState - , const AzToolsFramework::AngularManipulator::Action& action - , bool isFirstValue - , float& angleDelta - , AZ::Quaternion& manipulatorOrientation) - { - sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull(); - angleDelta = 0.0f; - AZ::Vector3 axis = m_axis; - sharedRotationState->m_savedOrientation.ConvertToAxisAngle(axis, angleDelta); - // Polarity of axis is switched by ConvertToAxisAngle call depending on direction of rotation - if (abs(m_axis.GetX() - 1.0f) < FLT_EPSILON) - { - angleDelta = AZ::RadToDeg(angleDelta) * axis.GetX(); - } - else if (abs(m_axis.GetY() - 1.0f) < FLT_EPSILON) - { - angleDelta = AZ::RadToDeg(angleDelta) * axis.GetY(); - } - else if (abs(m_axis.GetZ() - 1.0f) < FLT_EPSILON) - { - angleDelta = AZ::RadToDeg(angleDelta) * axis.GetZ(); - } - - manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; - - if (isFirstValue) - { - return sharedRotationState->m_valuePair.first + angleDelta; - } - else - { - return sharedRotationState->m_valuePair.second + angleDelta; - } - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.h deleted file mode 100644 index cb96570ebe..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.h +++ /dev/null @@ -1,66 +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 - -namespace PhysX -{ - class EditorSubComponentModeAnglePair - : public PhysX::EditorSubComponentModeBase - , private AzFramework::EntityDebugDisplayEventBus::Handler - { - public: - EditorSubComponentModeAnglePair( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , const AZ::Vector3& axis - , float firstMax - , float firstMin - , float secondMax - , float secondMin); - ~EditorSubComponentModeAnglePair(); - - // PhysX::EditorSubComponentModeBase - void Refresh() override; - - private: - struct SharedRotationState - { - AZ::Vector3 m_axis; - AZ::Quaternion m_savedOrientation = AZ::Quaternion::CreateIdentity(); - AngleLimitsFloatPair m_valuePair; - }; - - // AzFramework::EntityDebugDisplayEventBus - void DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; - - float MouseMove(AZStd::shared_ptr& sharedRotationState - , const AzToolsFramework::AngularManipulator::Action& action - , bool isFirstValue - , float& angleDelta - , AZ::Quaternion& manipulatorOrientation); - - AZStd::shared_ptr m_firstManipulator; - AZStd::shared_ptr m_secondManipulator; - - AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); - float m_firstMax = FLT_MAX; - float m_firstMin = -FLT_MAX; - float m_secondMax = FLT_MAX; - float m_secondMin = -FLT_MAX; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.cpp deleted file mode 100644 index 1e02d52859..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.cpp +++ /dev/null @@ -1,37 +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 - -namespace PhysX -{ - EditorSubComponentModeBase::EditorSubComponentModeBase( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name) - : m_entityComponentId(entityComponentIdPair), - m_name(name) - { - // The first time this is called, no object will respond to this bus call as no object is connected at the address, - // and m_jointTypeDrawer will remain as a nullptr. - EditorJointTypeDrawerBus::EventResult(m_jointTypeDrawer, - EditorJointTypeDrawerId(componentType, EditorSubComponentModeNameCrc(name)), - &EditorJointTypeDrawerBus::Events::GetEditorJointTypeDrawer); - - if (!m_jointTypeDrawer) - { - // Once this is called, the bus call to GetEditorJointTypeDrawer above will no longer get a null response, until m_jointTypeDrawer is destroyed. - m_jointTypeDrawer = AZStd::make_shared(componentType, - AzToolsFramework::GetEntityContextId(), - m_name); - } - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.h deleted file mode 100644 index 09e06927f3..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.h +++ /dev/null @@ -1,55 +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 AzFramework -{ - class DebugDisplayRequests; - struct ViewportInfo; -} - -namespace AzToolsFramework -{ - namespace ViewportInteraction - { - struct MouseInteractionEvent; - } -} - -namespace PhysX -{ - class EditorJointTypeDrawer; - - /// Base class for (joints) sub-component modes. - class EditorSubComponentModeBase - { - public: - EditorSubComponentModeBase( - const AZ::EntityComponentIdPair& entityComponentIdPair, - const AZ::Uuid& componentType, - const AZStd::string& name); - virtual ~EditorSubComponentModeBase() = default; - - /// Additional mouse handling by sub-component mode. Does not absorb mouse event. - virtual void HandleMouseInteraction( - [[maybe_unused]] const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) {}; - - virtual void Refresh() = 0; - - AZStd::string m_name;///< Name of sub-component mode. - - protected: - AZ::EntityComponentIdPair m_entityComponentId;///< Entity Id and component pair. - - private: - AZStd::shared_ptr m_jointTypeDrawer;///< Drawer that draws component type specific objects in the viewport. - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.cpp deleted file mode 100644 index 378e1fb982..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.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 - -namespace PhysX -{ - EditorSubComponentModeLinear::EditorSubComponentModeLinear( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , float exponent - , float max - , float min) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) - , m_exponent(exponent) - , m_inverseExponent(1.0f/exponent) - , m_max(max) - , m_min(min) - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - m_manipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); - m_manipulator->AddEntityComponentIdPair(m_entityComponentId); - m_manipulator->SetAxis(AZ::Vector3::CreateAxisX()); - m_manipulator->SetLocalTransform(localTransform); - - Refresh(); - - const AZ::Color manipulatorColor(0.3f, 0.3f, 0.3f, 1.0f); - const float manipulatorSize = 0.05f; - - AzToolsFramework::ManipulatorViews views; - views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(manipulatorColor - , manipulatorSize)); - m_manipulator->SetViews(AZStd::move(views)); - - struct SharedState - { - float m_startingValue = 0.0f; - }; - auto sharedState = AZStd::make_shared(); - - m_manipulator->InstallLeftMouseDownCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable - { - float currentValue = 0.0f; - - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValue - , m_name); - sharedState->m_startingValue = currentValue; - }); - - m_manipulator->InstallMouseMoveCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) - { - const float axisDisplacement = action.LocalPositionOffset().Dot(action.m_fixed.m_axis); - - float newValue = AZ::GetClamp(sharedState->m_startingValue + DisplacementToDeltaValue(axisDisplacement), m_min, m_max); - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValue - , m_name - , newValue); - - const AZ::Vector3 localPosition = action.LocalPosition().GetMax(AZ::Vector3(0.01f, 0.0f, 0.0f)); - m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(localPosition)); - m_manipulator->SetBoundsDirty(); - }); - - m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - } - - EditorSubComponentModeLinear::~EditorSubComponentModeLinear() - { - m_manipulator->Unregister(); - } - - void EditorSubComponentModeLinear::Refresh() - { - float currentValue = 0.0f; - - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValue - , m_name); - - m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX() * ValueToDisplacement(currentValue))); - } - - float EditorSubComponentModeLinear::DisplacementToDeltaValue(float displacement) const - { - if (displacement > 0.0f) - { - return powf(displacement, m_exponent); - } - else if (displacement < 0.0f) - { - return -powf(fabsf(displacement), m_exponent); - } - else - { - return 0.0f; - } - } - - float EditorSubComponentModeLinear::ValueToDisplacement(float value) const - { - return powf(value, m_inverseExponent); - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.h deleted file mode 100644 index 4d44d4aad4..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.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 - -#include - -namespace AzToolsFramework -{ - class LinearManipulator; -} - -namespace PhysX -{ - class EditorSubComponentModeLinear - : public PhysX::EditorSubComponentModeBase - { - public: - EditorSubComponentModeLinear( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , float exponent - , float max - , float min); - ~EditorSubComponentModeLinear(); - - // PhysX::EditorSubComponentModeBase - void Refresh() override; - - private: - float DisplacementToDeltaValue(float displacement) const; - float ValueToDisplacement(float value) const; - - float m_exponent = 1.0f; - float m_inverseExponent = 1.0f; - AZStd::shared_ptr m_manipulator; - float m_max = FLT_MAX; - float m_min = -FLT_MAX; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.cpp deleted file mode 100644 index 7586ecc955..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.cpp +++ /dev/null @@ -1,151 +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 - -namespace PhysX -{ - EditorSubComponentModeRotation::EditorSubComponentModeRotation( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) - { - CreateManipulators(); - RegisterManipulators(); - AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); - } - - EditorSubComponentModeRotation::~EditorSubComponentModeRotation() - { - AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); - UnregisterManipulators(); - } - - void EditorSubComponentModeRotation::Refresh() - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - for (auto rotationManipulator : m_rotationManipulators) - { - rotationManipulator->SetLocalTransform(localTransform); - rotationManipulator->SetBoundsDirty(); - } - } - - void EditorSubComponentModeRotation::DisplayEntityViewport( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, - [[maybe_unused]] AzFramework::DebugDisplayRequests& debugDisplay) - { - Refresh(); //Update position and orientation of manipulators. - } - - void EditorSubComponentModeRotation::CreateManipulators() - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - const AZ::Quaternion worldRotation = worldTransform.GetRotation(); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - const AZStd::array axes = { AZ::Vector3::CreateAxisX() - , AZ::Vector3::CreateAxisY() - , AZ::Vector3::CreateAxisZ()}; - - const AZStd::array colors = { AZ::Color(1.0f, 0.0f, 0.0f, 1.0f) - , AZ::Color(0.0f, 1.0f, 0.0f, 1.0f) - , AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)}; - - for (AZ::u32 i = 0; i < 3; ++i) - { - m_rotationManipulators[i] = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); - m_rotationManipulators[i]->AddEntityComponentIdPair(m_entityComponentId); - m_rotationManipulators[i]->SetAxis(axes[i]); - m_rotationManipulators[i]->SetLocalTransform(localTransform); - const float manipulatorRadius = 2.0f; - m_rotationManipulators[i]->SetView(AzToolsFramework::CreateManipulatorViewCircle( - *m_rotationManipulators[i], colors[i], manipulatorRadius, - AzToolsFramework::ManipulatorCicleBoundWidth(), AzToolsFramework::DrawHalfDottedCircle)); - } - - Refresh(); - InstallManipulatorMouseCallbacks(); - } - - void EditorSubComponentModeRotation::InstallManipulatorMouseCallbacks() - { - struct SharedState - { - AZ::Transform m_startTM; - }; - auto sharedState = AZStd::make_shared(); - - auto mouseDownRotateXCallback = [this, sharedState]([[maybe_unused]] const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - PhysX::EditorJointRequestBus::EventResult(sharedState->m_startTM - , m_entityComponentId - , &PhysX::EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - }; - - for (AZ::u32 index = 0; index < 3; ++index) - { - m_rotationManipulators[index]->InstallLeftMouseDownCallback(mouseDownRotateXCallback); - - m_rotationManipulators[index]->InstallMouseMoveCallback( - [this, index, sharedState] - (const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; - - AZ::Transform newTransform = AZ::Transform::CreateIdentity(); - newTransform = sharedState->m_startTM * AZ::Transform::CreateFromQuaternion(action.m_current.m_delta); - - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetVector3Value - , PhysX::EditorJointComponentMode::s_parameterRotation - , newTransform.GetRotation().GetEulerDegrees()); - - m_rotationManipulators[index]->SetLocalOrientation(manipulatorOrientation); - m_rotationManipulators[index]->SetBoundsDirty(); - }); - } - } - - void EditorSubComponentModeRotation::RegisterManipulators() - { - for (auto rotationManipulator : m_rotationManipulators) - { - rotationManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - } - } - - void EditorSubComponentModeRotation::UnregisterManipulators() - { - for (auto rotationManipulator : m_rotationManipulators) - { - rotationManipulator->Unregister(); - } - } -} diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.h deleted file mode 100644 index 349738909a..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.h +++ /dev/null @@ -1,48 +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 - -namespace AzToolsFramework -{ - class AngularManipulator; -} - -namespace PhysX -{ - class EditorSubComponentModeRotation - : public PhysX::EditorSubComponentModeBase - , private AzFramework::EntityDebugDisplayEventBus::Handler - { - public: - EditorSubComponentModeRotation( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name); - ~EditorSubComponentModeRotation(); - - // PhysX::EditorSubComponentModeBase - void Refresh() override; - - private: - // AzFramework::EntityDebugDisplayEventBus - void DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; - - void CreateManipulators(); - void InstallManipulatorMouseCallbacks(); - void RegisterManipulators(); - void UnregisterManipulators(); - - AZStd::array, 3> m_rotationManipulators; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.cpp deleted file mode 100644 index b086eb64ff..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.cpp +++ /dev/null @@ -1,97 +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 - -namespace PhysX -{ - EditorSubComponentModeSnapPosition::EditorSubComponentModeSnapPosition( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , bool selectLeadOnSnap) - : EditorSubComponentModeSnap(entityComponentIdPair, componentType, name) - , m_selectLeadOnSnap(selectLeadOnSnap) - { - InitMouseDownCallBack(); - m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); - } - - EditorSubComponentModeSnapPosition::~EditorSubComponentModeSnapPosition() - { - AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); - m_manipulator->Unregister(); - } - - void EditorSubComponentModeSnapPosition::DisplaySpecificSnapType( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay, - const AZ::Vector3& jointPosition, - const AZ::Vector3& snapDirection, - const float snapLength) - { - const float arrowLength = 1.0f; - const float iconGap = 1.0f; - const AZ::Vector3 iconPosition = jointPosition + - (snapDirection * (snapLength + arrowLength + iconGap)); - - debugDisplay.SetColor(AZ::Colors::Red); - debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(arrowLength, 0.0f, 0.0f)); - debugDisplay.SetColor(AZ::Colors::Green); - debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(0.2f, arrowLength, 0.2f)); - debugDisplay.SetColor(AZ::Colors::Blue); - debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(0.0f, 0.0f, arrowLength)); - } - - void EditorSubComponentModeSnapPosition::InitMouseDownCallBack() - { - m_manipulator->InstallLeftMouseDownCallback( - [this](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable - { - if (!m_pickedEntity.IsValid()) - { - return; - } - - const AZ::Vector3 newLocalPosition = PhysX::Utils::ComputeJointLocalTransform( - PhysX::Utils::GetEntityWorldTransformWithScale(m_pickedEntity), - PhysX::Utils::GetEntityWorldTransformWithScale(m_entityComponentId.GetEntityId())).GetTranslation(); - - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetVector3Value - , PhysX::EditorJointComponentMode::s_parameterPosition - , newLocalPosition); - - const bool selectedEntityIsNotJointEntity = m_pickedEntity != m_entityComponentId.GetEntityId(); - - AZ_Error("EditorSubComponentModeSnapPosition", - selectedEntityIsNotJointEntity, - "Joint's lead entity cannot be the same as the entity in which the joint resides. Select lead entity on snap failed."); - - if (m_selectLeadOnSnap && - selectedEntityIsNotJointEntity) - { - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetEntityIdValue - , PhysX::EditorJointComponentMode::s_parameterLeadEntity - , m_pickedEntity); - } - - m_manipulator->SetBoundsDirty(); - }); - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.h deleted file mode 100644 index d2fe803431..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.h +++ /dev/null @@ -1,42 +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 PhysX -{ - /// This sub-component mode gets an entity position from its base class on mouse down - /// and sets a position (AZ::Vector3) value in the component that uses it. - class EditorSubComponentModeSnapPosition - : public EditorSubComponentModeSnap - { - public: - EditorSubComponentModeSnapPosition( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , bool selectLeadOnSnap); - ~EditorSubComponentModeSnapPosition() override; - - protected: - // PhysX::EditorSubComponentModeSnap - void DisplaySpecificSnapType( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay, - const AZ::Vector3& jointPosition, - const AZ::Vector3& snapDirection, - float snapLength) override; - - void InitMouseDownCallBack() override; - - private: - bool m_selectLeadOnSnap = true; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.cpp deleted file mode 100644 index c68e058e29..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.cpp +++ /dev/null @@ -1,122 +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 PhysX -{ - EditorSubComponentModeSnapRotation::EditorSubComponentModeSnapRotation( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name) - : EditorSubComponentModeSnap(entityComponentIdPair, componentType, name) - { - InitMouseDownCallBack(); - m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); - } - - EditorSubComponentModeSnapRotation::~EditorSubComponentModeSnapRotation() - { - AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); - m_manipulator->Unregister(); - } - - void EditorSubComponentModeSnapRotation::DisplaySpecificSnapType( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay, - const AZ::Vector3& jointPosition, - const AZ::Vector3& snapDirection, - const float snapLength) - { - const float circleRadius = 0.5f; - const float iconGap = 1.0f; - - const AZ::Vector3 iconPosition = jointPosition + - (snapDirection * (snapLength + circleRadius * 2.0f + iconGap)); - - debugDisplay.SetColor(AZ::Colors::Red); - debugDisplay.DrawCircle(iconPosition, circleRadius, 0); - debugDisplay.SetColor(AZ::Colors::Green); - debugDisplay.DrawCircle(iconPosition, circleRadius, 1); - debugDisplay.SetColor(AZ::Colors::Blue); - debugDisplay.DrawCircle(iconPosition, circleRadius, 2); - } - - void EditorSubComponentModeSnapRotation::InitMouseDownCallBack() - { - m_manipulator->InstallLeftMouseDownCallback( - [this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action) mutable - { - if (!m_pickedEntity.IsValid()) - { - return; - } - - AZ::EntityId leadEntityId; - PhysX::EditorJointRequestBus::EventResult(leadEntityId, - m_entityComponentId, - &PhysX::EditorJointRequests::GetEntityIdValue, - PhysX::EditorJointComponentMode::s_parameterLeadEntity); - - if (leadEntityId.IsValid() && m_pickedEntity == leadEntityId) - { - AZ_Warning("EditorsubComponentModeSnapRotation", - false, - "The entity %s is the lead of the joint. Please snap rotation (or orientation) of joint to another entity that is not the lead entity.", - GetPickedEntityName().c_str()); - return; - } - - AZ::Transform worldTransform = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldTransform, m_entityComponentId.GetEntityId(), &AZ::TransformInterface::GetWorldTM); - worldTransform.ExtractUniformScale(); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - AZ::Transform pickedEntityTransform = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - pickedEntityTransform, m_pickedEntity, &AZ::TransformInterface::GetWorldTM); - - const AZ::Transform worldTransformInv = worldTransform.GetInverse(); - const AZ::Vector3 pickedLocalPosition = worldTransformInv.TransformVector(pickedEntityTransform.GetTranslation()) - localTransform.GetTranslation(); - - if (abs(pickedLocalPosition.GetLength()) < FLT_EPSILON) - { - AZ_Warning("EditorsubComponentModeSnapRotation", - false, - "The entity %s is too close to the joint position. Please snap rotation to an entity that is not at the position of the joint.", - GetPickedEntityName().c_str()); - return; - } - - const AZ::Vector3 targetDirection = pickedLocalPosition.GetNormalized(); - const AZ::Vector3 sourceDirection = AZ::Vector3::CreateAxisX(); - const AZ::Quaternion newLocalRotation = AZ::Quaternion::CreateShortestArc(sourceDirection, targetDirection); - - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetVector3Value - , PhysX::EditorJointComponentMode::s_parameterRotation //using rotation parameter name to set the local rotation value - , newLocalRotation.GetEulerDegrees()); - - m_manipulator->SetBoundsDirty(); - }); - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.h deleted file mode 100644 index 06d41df206..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.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 - -#include - -namespace PhysX -{ - /// TThis sub-component mode gets an entity position from its base class on mouse down - /// and sets a rotation (AZ::Quaternion) value in the component that uses it. - class EditorSubComponentModeSnapRotation - : public EditorSubComponentModeSnap - { - public: - EditorSubComponentModeSnapRotation( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name); - ~EditorSubComponentModeSnapRotation() override; - - protected: - // PhysX::EditorSubComponentModeSnap - void DisplaySpecificSnapType( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay, - const AZ::Vector3& jointPosition, - const AZ::Vector3& snapDirection, - float snapLength) override; - - void InitMouseDownCallBack() override; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.cpp deleted file mode 100644 index 7e8affb086..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.cpp +++ /dev/null @@ -1,91 +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 PhysX -{ - EditorSubComponentModeVec3::EditorSubComponentModeVec3( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) - , m_translationManipulators(AzToolsFramework::TranslationManipulators::Dimensions::Three, - AZ::Transform::Identity(), AZ::Vector3::CreateOne()) - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Vector3 localTranslation; - EditorJointRequestBus::EventResult( - localTranslation, m_entityComponentId - , &EditorJointRequests::GetVector3Value - , m_name); - - m_translationManipulators.SetSpace(worldTransform); - m_translationManipulators.SetLocalPosition(localTranslation); - m_translationManipulators.AddEntityComponentIdPair(m_entityComponentId); - - m_translationManipulators.Register(AzToolsFramework::g_mainManipulatorManagerId); - - AzToolsFramework::ConfigureTranslationManipulatorAppearance3d(&m_translationManipulators); - - m_translationManipulators.InstallLinearManipulatorMouseMoveCallback([this]( - const AzToolsFramework::LinearManipulator::Action& action) - { - OnManipulatorMoved(action.LocalPosition()); - }); - - m_translationManipulators.InstallPlanarManipulatorMouseMoveCallback([this]( - const AzToolsFramework::PlanarManipulator::Action& action) - { - OnManipulatorMoved(action.LocalPosition()); - }); - - m_translationManipulators.InstallSurfaceManipulatorMouseMoveCallback([this]( - const AzToolsFramework::SurfaceManipulator::Action& action) - { - OnManipulatorMoved(action.LocalPosition()); - }); - } - - EditorSubComponentModeVec3::~EditorSubComponentModeVec3() - { - m_translationManipulators.Unregister(); - } - - void EditorSubComponentModeVec3::Refresh() - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Vector3 localTranslation; - EditorJointRequestBus::EventResult( - localTranslation, m_entityComponentId - , &EditorJointRequests::GetVector3Value - , m_name); - - m_translationManipulators.SetSpace(worldTransform); - m_translationManipulators.SetLocalPosition(localTranslation); - m_translationManipulators.SetBoundsDirty(); - } - - void EditorSubComponentModeVec3::OnManipulatorMoved(const AZ::Vector3& position) - { - m_translationManipulators.SetLocalPosition(position); - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetVector3Value - , m_name - , position); - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.h deleted file mode 100644 index 849125eb1c..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.h +++ /dev/null @@ -1,34 +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 - -namespace PhysX -{ - class EditorSubComponentModeVec3 - : public PhysX::EditorSubComponentModeBase - { - public: - EditorSubComponentModeVec3( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name); - ~EditorSubComponentModeVec3(); - - // PhysX::EditorSubComponentModeBase - void Refresh() override; - - private: - void OnManipulatorMoved(const AZ::Vector3& position); - - AzToolsFramework::TranslationManipulators m_translationManipulators; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp new file mode 100644 index 0000000000..ce95e27db3 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp @@ -0,0 +1,601 @@ +/* + * 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 + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsComponentMode, AZ::SystemAllocator, 0); + + namespace SubModeData + { + const AZ::Crc32 SwitchToTranslationSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtotranslationsubmode"); + static const char* TranslationTitle = "Switch to Position Mode"; + static const char* TranslationToolTip = "Position Mode - Change the position of the joint."; + + const AZ::Crc32 SwitchToRotationSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtorotationsubmode"); + static const char* RotationTitle = "Switch to Rotation Mode"; + static const char* RotationToolTip = "Rotation Mode- Change the rotation of the joint."; + + const AZ::Crc32 SwitchToMaxForceSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtomaxforce"); + static const char* MaxForceTitle = "Switch to Max Force Mode"; + static const char* MaxForceToolTip = "Max Force Mode - Change the maximum force allowed before the joint breaks."; + + const AZ::Crc32 SwitchToMaxTorqueSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtomaxtorque"); + static const char* MaxTorqueTitle = "Switch to Max Torque Mode"; + static const char* MaxTorqueToolTip = "Max Torque Mode - Change the maximum torque allowed before the joint breaks."; + + const AZ::Crc32 SwitchToDampingSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtodamping"); + static const char* DampingTitle = "Switch to Damping Mode"; + static const char* DampingToolTip = "Damping Mode - Change the damping strength of the joint when beyond the limit."; + + const AZ::Crc32 SwitchToStiffnessSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtostiffness"); + static const char* StiffnessTitle = "Switch to Stiffness Mode"; + static const char* StiffnessToolTip = "Stiffness Mode - Change the stiffness strength of the joint when beyond the limit."; + + const AZ::Crc32 SwitchToTwistLimitsSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtotwistlimits"); + static const char* TwistLimitsTitle = "Switch to Twist Limits Mode"; + static const char* TwistLimitsToolTip = "Twist Limits Mode - Change the limits of the joint."; + + const AZ::Crc32 SwitchToSwingLimitsSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtoswinglimits"); + static const char* SwingLimitsTitle = "Switch to Swing Limits Mode"; + static const char* SwingLimitsToolTip = "Swing Limits Mode - Change the limits of the joint."; + + const AZ::Crc32 SwitchToSnapPositionSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtosnapposition"); + static const char* SnapPositionTitle = "Switch to Snap Position Mode"; + static const char* SnapPositionToolTip = "Snap Position Mode - Snap the position of the joint to another Entity."; + + const AZ::Crc32 SwitchToSnapRotationSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtosnaprotation"); + static const char* SnapRotationTitle = "Switch to Snap Rotation Mode"; + static const char* SnapRotationToolTip = "Snap Rotation Mode - Snap the rotation of the joint toward another Entity."; + + const AZ::Crc32 ResetSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.resetsubmode"); + static const char* ResetTitle = "Reset Current Mode"; + static const char* ResetToolTip = "Reset changes made during this mode edit."; + + } // namespace ActionData + + namespace Internal + { + static AzToolsFramework::ViewportUi::ButtonId RegisterClusterButton( + AzToolsFramework::ViewportUi::ClusterId clusterId, const char* iconName, const char* tooltip) + { + AzToolsFramework::ViewportUi::ButtonId buttonId; + AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( + buttonId, AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateClusterButton, clusterId, + AZStd::string::format(":/stylesheet/img/UI20/toolbar/%s.svg", iconName)); + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonTooltip, clusterId, buttonId, tooltip); + + return buttonId; + } + + void RefreshUI() + { + // The reason this is in a free function is because ColliderComponentMode + // privately inherits from ToolsApplicationNotificationBus. Trying to invoke + // the bus inside the class scope causes the compiler to complain it's not accessible + // to due private inheritance. + // Using the global namespace operator :: should have fixed that, except there + // is a bug in the Microsoft compiler meaning it doesn't work. So this is a work around. + AzToolsFramework::ToolsApplicationNotificationBus::Broadcast( + &AzToolsFramework::ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values); + } + } // namespace Internal + + JointsComponentMode::JointsComponentMode(const AZ::EntityComponentIdPair& entityComponentIdPair, AZ::Uuid componentType) + : AzToolsFramework::ComponentModeFramework::EditorBaseComponentMode(entityComponentIdPair, componentType) + { + m_modeSelectionClusterIds.assign(static_cast(ClusterGroups::GroupCount), AzToolsFramework::ViewportUi::InvalidClusterId); + SetupSubModes(entityComponentIdPair); + + EditorJointRequestBus::Event( + entityComponentIdPair, &EditorJointRequests::SetBoolValue, JointsComponentModeCommon::ParamaterNames::ComponentMode, true); + } + + JointsComponentMode::~JointsComponentMode() + { + EditorJointRequestBus::Event( + GetEntityComponentIdPair(), &EditorJointRequests::SetBoolValue, JointsComponentModeCommon::ParamaterNames::ComponentMode, + false); + + TeardownSubModes(); + m_subModes[m_subMode]->Teardown(GetEntityComponentIdPair()); + } + + void JointsComponentMode::Refresh() + { + m_subModes[m_subMode]->Refresh(GetEntityComponentIdPair()); + } + + AZStd::vector JointsComponentMode::PopulateActionsImpl() + { + const AZ::EntityComponentIdPair entityComponentIdPair = GetEntityComponentIdPair(); + + AZStd::vector subModesState; + EditorJointRequestBus::EventResult(subModesState, entityComponentIdPair, &EditorJointRequests::GetSubComponentModesState); + + auto makeActionOverride = [](const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Crc32& actionUri, + const QString& title, const QString& tip,const AZStd::function&& callback) + { + AzToolsFramework::ActionOverride actionOverride; + actionOverride.SetTitle(title); + actionOverride.SetTip(tip); + actionOverride.SetUri(actionUri); + actionOverride.SetEntityComponentIdPair(entityComponentIdPair); + actionOverride.SetCallback(callback); + return actionOverride; + }; + + AZStd::vector actions; + + // translation action + { + AzToolsFramework::ActionOverride translateAction = makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToTranslationSubMode, + SubModeData::TranslationTitle, SubModeData::TranslationToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::Translation, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Translation]); + }); + translateAction.SetKeySequence(QKeySequence(Qt::Key_1)); + actions.emplace_back(translateAction); + } + + // rotation action + { + AzToolsFramework::ActionOverride rotationAction = makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToRotationSubMode, + SubModeData::RotationTitle, SubModeData::RotationToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::Rotation, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Rotation]); + }); + rotationAction.SetKeySequence(QKeySequence(Qt::Key_2)); + actions.emplace_back(rotationAction); + } + + //setup action for other enabled options + for (auto [modeType, parameterString] : subModesState) + { + switch (modeType) + { + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToMaxForceSubMode, + SubModeData::MaxForceTitle, SubModeData::MaxForceToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToMaxTorqueSubMode, + SubModeData::MaxTorqueTitle, SubModeData::MaxTorqueToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::Damping: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToDampingSubMode, + SubModeData::DampingTitle, SubModeData::DampingToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::Damping, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Damping]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToStiffnessSubMode, + SubModeData::StiffnessTitle, SubModeData::StiffnessToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToTwistLimitsSubMode, + SubModeData::TwistLimitsTitle, SubModeData::TwistLimitsToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToSwingLimitsSubMode, + SubModeData::SwingLimitsTitle, SubModeData::SwingLimitsToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToSnapPositionSubMode, + SubModeData::SnapPositionTitle, SubModeData::SnapPositionToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToSnapRotationSubMode, + SubModeData::SnapRotationTitle, SubModeData::SnapRotationToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation]); + })); + } + break; + } + } + + // reset values + { + AzToolsFramework::ActionOverride resetValuesAction = makeActionOverride( + entityComponentIdPair, SubModeData::ResetSubMode, + SubModeData::ResetTitle, SubModeData::ResetToolTip, + [this]() + { + ResetCurrentMode(); + }); + resetValuesAction.SetKeySequence(QKeySequence(Qt::Key_R)); + actions.emplace_back(resetValuesAction); + } + + return actions; + } + + AZStd::vector JointsComponentMode::PopulateViewportUiImpl() + { + return AZStd::vector(m_modeSelectionClusterIds.begin(), m_modeSelectionClusterIds.end()); + } + + void JointsComponentMode::SetCurrentMode(JointsComponentModeCommon::SubComponentModes::ModeType newMode, ButtonData& buttonData) + { + + if (auto subMode = m_subModes.find(newMode); + subMode != m_subModes.end()) + { + const AZ::EntityComponentIdPair entityComponentIdPair = GetEntityComponentIdPair(); + m_subModes[m_subMode]->Teardown(entityComponentIdPair); + m_subMode = newMode; + subMode->second->Setup(entityComponentIdPair); + + // if this button is on a different cluster. clear the active state. + if (m_activeButton.m_clusterId != buttonData.m_clusterId) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::ClearClusterActiveButton, m_activeButton.m_clusterId); + } + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, buttonData.m_clusterId, + buttonData.m_buttonId); + m_activeButton = buttonData; + } + else + { + AZ_Assert(false, "PhysXJoints Uninitialized joint component mode selected."); + } + } + + bool JointsComponentMode::HandleMouseInteraction(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) + { + // Propagate mouse interaction to sub-component mode. + if (m_subModes[m_subMode]) + { + m_subModes[m_subMode]->HandleMouseInteraction(mouseInteraction); + } + + return false; + } + + void JointsComponentMode::SetupSubModes(const AZ::EntityComponentIdPair& entityComponentIdPair) + { + //create the 3 cluster groups + for (auto& clusterId : m_modeSelectionClusterIds) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( + clusterId, AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, + AzToolsFramework::ViewportUi::Alignment::TopLeft); + } + + //retrieve the enabled sub components from the entity + AZStd::vector subModesState; + EditorJointRequestBus::EventResult(subModesState, entityComponentIdPair, &EditorJointRequests::GetSubComponentModesState); + + const AzToolsFramework::ViewportUi::ClusterId group1ClusterId = GetClusterId(ClusterGroups::Group1); + const AzToolsFramework::ViewportUi::ClusterId group2ClusterId = GetClusterId(ClusterGroups::Group2); + //hide cluster 2, if something is added to it. it will make is visible + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, + group2ClusterId, false); + + const AzToolsFramework::ViewportUi::ClusterId group3ClusterId = GetClusterId(ClusterGroups::Group3); + // hide cluster 3, if something is added to it. it will make is visible + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, + group3ClusterId, false); + + //translation and rotation are enabled for all joints in group 1 + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Translation] = + AZStd::make_unique(); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Translation] = + ButtonData{ group1ClusterId, Internal::RegisterClusterButton(group1ClusterId, "Move", SubModeData::TranslationToolTip) }; + + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Rotation] = AZStd::make_unique(); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Rotation] = + ButtonData{ group1ClusterId, Internal::RegisterClusterButton(group1ClusterId, "Rotate", SubModeData::RotationTitle) }; + + //some constants for some modes + const float ExponentBreakage = 1.0f; + const float ExponentSpring = 2.0f; + + //setup the remaining modes if they're in the enabled list. + for (auto [modeType, parameterString] : subModesState) + { + switch (modeType) + { + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce] = + AZStd::make_unique( + parameterString, ExponentBreakage, EditorJointConfig::s_breakageMax, EditorJointConfig::s_breakageMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group3ClusterId, "joints/MaxForce", SubModeData::MaxForceToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce] = + ButtonData{ group3ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group3ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque] = + AZStd::make_unique( + parameterString, ExponentBreakage, EditorJointConfig::s_breakageMax, EditorJointConfig::s_breakageMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group3ClusterId, "joints/MaxTorque", SubModeData::MaxTorqueToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque] = + ButtonData{ group3ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group3ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::Damping: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Damping] = + AZStd::make_unique( + parameterString, ExponentSpring, EditorJointLimitBase::s_springMax, EditorJointLimitBase::s_springMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group2ClusterId, "joints/Damping", SubModeData::DampingToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Damping] = ButtonData{ group2ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness] = + AZStd::make_unique( + parameterString, ExponentSpring, EditorJointLimitBase::s_springMax, EditorJointLimitBase::s_springMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group2ClusterId, "joints/Stiffness", SubModeData::StiffnessToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness] = + ButtonData{ group2ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits] = + AZStd::make_unique( + parameterString, + AZ::Vector3::CreateAxisX(), // PhysX revolute joints uses the x-axis by default + EditorJointLimitPairConfig::s_angleMax, EditorJointLimitPairConfig::s_angleMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group2ClusterId, "joints/TwistLimits", SubModeData::TwistLimitsToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits] = + ButtonData{ group2ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits] = + AZStd::make_unique( + parameterString, EditorJointLimitPairConfig::s_angleMax, EditorJointLimitPairConfig::s_angleMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group2ClusterId, "joints/SwingLimits", SubModeData::SwingLimitsToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits] = + ButtonData{ group2ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition] = + AZStd::make_unique(); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group1ClusterId, "joints/SnapPosition", SubModeData::SnapPositionToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition] = + ButtonData{ group1ClusterId, buttonId }; + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation] = + AZStd::make_unique(); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group1ClusterId, "joints/SnapRotation", SubModeData::SnapRotationToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation] = + ButtonData{ group1ClusterId, buttonId }; + } + break; + } + } + + //register click handler for the buttons + m_modeSelectionHandlers.push_back(AZ::Event::Handler( + [this](AzToolsFramework::ViewportUi::ButtonId buttonId) + { + for (auto itr : m_buttonData) + { + if (itr.second.m_clusterId == GetClusterId(ClusterGroups::Group1) && itr.second.m_buttonId == buttonId) + { + SetCurrentMode(itr.first, itr.second); + break; + } + } + })); + m_modeSelectionHandlers.push_back(AZ::Event::Handler( + [this](AzToolsFramework::ViewportUi::ButtonId buttonId) + { + for (auto itr : m_buttonData) + { + if (itr.second.m_clusterId == GetClusterId(ClusterGroups::Group2) && itr.second.m_buttonId == buttonId) + { + SetCurrentMode(itr.first, itr.second); + break; + } + } + })); + m_modeSelectionHandlers.push_back(AZ::Event::Handler( + [this](AzToolsFramework::ViewportUi::ButtonId buttonId) + { + for (auto itr : m_buttonData) + { + if (itr.second.m_clusterId == GetClusterId(ClusterGroups::Group3) && itr.second.m_buttonId == buttonId) + { + SetCurrentMode(itr.first, itr.second); + break; + } + } + })); + + for (int i = 0; i < static_cast(ClusterGroups::GroupCount); i++) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, m_modeSelectionClusterIds[i], + m_modeSelectionHandlers[i]); + } + + // set the translate as enabled by default. + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::Translation, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Translation]); + + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Translation]->Setup(GetEntityComponentIdPair()); + m_subMode = JointsComponentModeCommon::SubComponentModes::ModeType::Translation; + } + + void JointsComponentMode::ResetCurrentMode() + { + const AZ::EntityComponentIdPair entityComponentIdPair = GetEntityComponentIdPair(); + m_subModes[m_subMode]->ResetValues(entityComponentIdPair); + m_subModes[m_subMode]->Refresh(entityComponentIdPair); + + Internal::RefreshUI(); + } + + void JointsComponentMode::TeardownSubModes() + { + for (auto clusterid : m_modeSelectionClusterIds) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, + clusterid); + } + } + + AzToolsFramework::ViewportUi::ClusterId JointsComponentMode::GetClusterId(ClusterGroups group) + { + return m_modeSelectionClusterIds[static_cast(group)]; + } +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.h new file mode 100644 index 0000000000..812bc71ec1 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.h @@ -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 + * + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace AZ +{ + class EntityComponentIdPair; +} + +namespace PhysX +{ + //! Class responsible for managing component mode for joints. + class JointsComponentMode final + : public AzToolsFramework::ComponentModeFramework::EditorBaseComponentMode + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsComponentMode(const AZ::EntityComponentIdPair& entityComponentIdPair, AZ::Uuid componentType); + ~JointsComponentMode(); + + // EditorBaseComponentMode ... + void Refresh() override; + AZStd::vector PopulateActionsImpl() override; + AZStd::vector PopulateViewportUiImpl() override; + private: + //! Used to identify the group of component modes. + enum class ClusterGroups + { + Group1 = 0, //!< Position Joint, Rotate Joint, Snap Position, Snap Rotation. + Group2, //!< Damping, Stiffness, Twist Limits, Swing Limits. + Group3, //!< Max Force, Max Torque. + + GroupCount + }; + + //! Used to track the cluster that a specific button is apart of. + struct ButtonData + { + AzToolsFramework::ViewportUi::ClusterId m_clusterId; + AzToolsFramework::ViewportUi::ButtonId m_buttonId; + }; + + void SetCurrentMode(JointsComponentModeCommon::SubComponentModes::ModeType newMode, ButtonData& buttonData); + bool HandleMouseInteraction(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; + void SetupSubModes(const AZ::EntityComponentIdPair& entityComponentIdPair); + void ResetCurrentMode(); + void TeardownSubModes(); + + AzToolsFramework::ViewportUi::ClusterId GetClusterId(ClusterGroups group); + + AZStd::fixed_vector(ClusterGroups::GroupCount)> m_modeSelectionClusterIds; //!< List of the cluster ui's. The sub modes are split across 3 groups and each group is it's own cluster ui. + AZStd::unordered_map m_buttonData; //!< Mapping of joint component modes to the button data. + + AZStd::fixed_vector::Handler, static_cast(ClusterGroups::GroupCount)> + m_modeSelectionHandlers; //!< Input handlers for each cluster UI. + ButtonData m_activeButton; //!< The current highlighted button data. + + JointsComponentModeCommon::SubComponentModes::ModeType m_subMode = JointsComponentModeCommon::SubComponentModes::ModeType::Translation; //!< The current component mode that is active. + AZStd::unordered_map> m_subModes; //!< The logic handlers for each component mode. + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.cpp new file mode 100644 index 0000000000..a400745c51 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.cpp @@ -0,0 +1,27 @@ +/* + * 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 PhysX::JointsComponentModeCommon +{ + const AZStd::string_view ParamaterNames::TwistLimits = "Twist Limits"; + const AZStd::string_view ParamaterNames::Damping = "Damping"; + const AZStd::string_view ParamaterNames::MaxForce = "Maximum Force"; + const AZStd::string_view ParamaterNames::MaxTorque = "Maximum Torque"; + const AZStd::string_view ParamaterNames::Position = "Position"; + const AZStd::string_view ParamaterNames::Rotation = "Rotation"; + const AZStd::string_view ParamaterNames::SnapPosition = "Snap Position"; + const AZStd::string_view ParamaterNames::SnapRotation = "Snap Rotation"; + const AZStd::string_view ParamaterNames::Stiffness = "Stiffness"; + const AZStd::string_view ParamaterNames::SwingLimit = "Swing Limits"; + const AZStd::string_view ParamaterNames::Transform = "Transform"; + const AZStd::string_view ParamaterNames::ComponentMode = "Component Mode"; + const AZStd::string_view ParamaterNames::LeadEntity = "Lead Entity"; + +} // namespace PhysX::JointsComponentModeCommon diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.h new file mode 100644 index 0000000000..3deb3b7e3f --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.h @@ -0,0 +1,70 @@ +/* + * 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 + +namespace PhysX::JointsComponentModeCommon +{ + namespace SubComponentModes + { + //! Used to identify a specific sub component mode used with joints + enum class ModeType : AZ::u32 + { + Translation = 0, + Rotation, + MaxForce, + MaxTorque, + Damping, + Stiffness, + TwistLimits, + SwingLimits, + SnapPosition, + SnapRotation, + + ModeCount + }; + + //! Shared data structure used with Angle Cone and Angle Pair sub component modes. + //! Holds information about the axis and limits of the angle. + struct AngleModesSharedRotationState + { + AZ::Vector3 m_axis; //!< The Axis of rotation to apply the limits. + AZ::Quaternion m_savedOrientation = AZ::Quaternion::CreateIdentity(); //!< The angle delta of the last mouse action. + PhysX::AngleLimitsFloatPair m_valuePair; //!< the current limits of the angle. + }; + } // namespace SubComponentModes + + //! Name Identifiers for the joint components sub modes. + struct ParamaterNames + { + static const AZStd::string_view TwistLimits; + static const AZStd::string_view Damping; + static const AZStd::string_view MaxForce; + static const AZStd::string_view MaxTorque; + static const AZStd::string_view Position; + static const AZStd::string_view Rotation; + static const AZStd::string_view SnapPosition; + static const AZStd::string_view SnapRotation; + static const AZStd::string_view Stiffness; + static const AZStd::string_view SwingLimit; + static const AZStd::string_view Transform; + static const AZStd::string_view ComponentMode; + static const AZStd::string_view LeadEntity; + }; + + //! A pairing of Sub component Names, and Id. + struct SubModeParamaterState + { + SubComponentModes::ModeType m_modeType = SubComponentModes::ModeType::ModeCount; //!< The Id of the sub component mode. + AZStd::string m_parameterName; //!< The name of the sub component mode. + }; +} // namespace PhysX::JointsComponentModeCommon diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp new file mode 100644 index 0000000000..11abe0fa2a --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp @@ -0,0 +1,432 @@ +/* + * 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 + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeAngleCone, AZ::SystemAllocator, 0); + + namespace Internal + { + const float ArrowLength = 2.0f; + const float ConeHeight = 3.0f; + const float XRotationManipulatorRadius = 2.0f; + const float XRotationManipulatorWidth = 0.05f; + } // namespace Internal + + JointsSubComponentModeAngleCone::JointsSubComponentModeAngleCone( + const AZStd::string& propertyName, float max, float min) + : m_propertyName(propertyName) + , m_max(max) + , m_min(min) + { + + } + + void JointsSubComponentModeAngleCone::Setup(const AZ::EntityComponentIdPair& idPair) + { + m_entityComponentIdPair = idPair; + EditorJointRequestBus::EventResult( + m_resetPostion, m_entityComponentIdPair, &PhysX::EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Position); + EditorJointRequestBus::EventResult( + m_resetRotation, m_entityComponentIdPair, &PhysX::EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation); + EditorJointRequestBus::EventResult( + m_resetLimits, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentIdPair.GetEntityId()); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + const AZ::Quaternion localRotation = localTransform.GetRotation(); + + // Initialize manipulators used to resize the base of the cone. + m_yLinearManipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); + m_yLinearManipulator->AddEntityComponentIdPair(m_entityComponentIdPair); + m_yLinearManipulator->SetAxis(AZ::Vector3::CreateAxisZ()); + + m_zLinearManipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); + m_zLinearManipulator->AddEntityComponentIdPair(m_entityComponentIdPair); + m_zLinearManipulator->SetAxis(AZ::Vector3::CreateAxisY()); + + m_yzPlanarManipulator = AzToolsFramework::PlanarManipulator::MakeShared(worldTransform); + m_yzPlanarManipulator->AddEntityComponentIdPair(m_entityComponentIdPair); + m_yzPlanarManipulator->SetAxes(AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + + ConfigureLinearView( + Internal::ArrowLength, AZ::Color(1.0f, 0.0f, 0.0f, 1.0f), AZ::Color(0.0f, 1.0f, 0.0f, 1.0f), AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)); + + ConfigurePlanarView(AZ::Color(0.0f, 1.0f, 0.0f, 1.0f), AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)); + + // Position and orientate manipulators + AZ::Transform displacementTransform = localTransform; + AZ::Vector3 displacementTranslate = localRotation.TransformVector(AZ::Vector3(Internal::ConeHeight, 0.0f, 0.0f)); + displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); + + m_yLinearManipulator->SetLocalTransform(displacementTransform); + m_zLinearManipulator->SetLocalTransform(displacementTransform); + m_yzPlanarManipulator->SetLocalTransform(displacementTransform); + + // Initialize rotation manipulator for rotating cone + m_xRotationManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); + m_xRotationManipulator->AddEntityComponentIdPair(m_entityComponentIdPair); + m_xRotationManipulator->SetAxis(AZ::Vector3::CreateAxisX()); + m_xRotationManipulator->SetLocalTransform(localTransform); + + const AZ::Color xRotationManipulatorColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f); + m_xRotationManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( + *m_xRotationManipulator, xRotationManipulatorColor, Internal::XRotationManipulatorRadius, Internal::XRotationManipulatorWidth, + AzToolsFramework::DrawHalfDottedCircle)); + + AZStd::shared_ptr sharedRotationState = + AZStd::make_shared(); + + struct SharedState + { + AngleLimitsFloatPair m_startValues; + }; + auto sharedState = AZStd::make_shared(); + + m_yLinearManipulator->InstallLeftMouseDownCallback( + [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable + { + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult( + currentValue, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + sharedState->m_startValues = currentValue; + }); + + m_yLinearManipulator->InstallMouseMoveCallback( + [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, + JointsComponentModeCommon::ParamaterNames::Transform); + const AZ::Quaternion localRotation = localTransform.GetRotation(); + const float axisDisplacement = action.LocalPositionOffset().Dot(localRotation.TransformVector(action.m_fixed.m_axis)); + const float originalBaseY = tan(AZ::DegToRad(sharedState->m_startValues.first)) * Internal::ConeHeight; + const float newBaseY = originalBaseY + axisDisplacement; + const float newAngle = AZ::GetClamp(AZ::RadToDeg(atan(newBaseY / Internal::ConeHeight)), m_min, m_max); + + EditorJointRequestBus::Event( + m_entityComponentIdPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, + AngleLimitsFloatPair(newAngle, sharedState->m_startValues.second)); + + m_yLinearManipulator->SetBoundsDirty(); + }); + + m_zLinearManipulator->InstallLeftMouseDownCallback( + [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable + { + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult( + currentValue, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + sharedState->m_startValues = currentValue; + }); + + m_zLinearManipulator->InstallMouseMoveCallback( + [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, + JointsComponentModeCommon::ParamaterNames::Transform); + const AZ::Quaternion localRotation = localTransform.GetRotation(); + const float axisDisplacement = action.LocalPositionOffset().Dot(localRotation.TransformVector(action.m_fixed.m_axis)); + const float originalBaseZ = tan(AZ::DegToRad(sharedState->m_startValues.second)) * Internal::ConeHeight; + const float newBaseZ = originalBaseZ + axisDisplacement; + const float newAngle = AZ::GetClamp(AZ::RadToDeg(atan(newBaseZ / Internal::ConeHeight)), m_min, m_max); + + EditorJointRequestBus::Event( + m_entityComponentIdPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, + AngleLimitsFloatPair(sharedState->m_startValues.first, newAngle)); + + m_zLinearManipulator->SetBoundsDirty(); + }); + + m_yzPlanarManipulator->InstallLeftMouseDownCallback( + [this, sharedState]([[maybe_unused]]const AzToolsFramework::PlanarManipulator::Action& action) mutable + { + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult( + currentValue, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + sharedState->m_startValues = currentValue; + }); + + m_yzPlanarManipulator->InstallMouseMoveCallback( + [this, sharedState](const AzToolsFramework::PlanarManipulator::Action& action) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, + JointsComponentModeCommon::ParamaterNames::Transform); + + const AZ::Quaternion localRotation = localTransform.GetRotation(); + + const float axisDisplacementY = action.LocalPositionOffset().Dot(localRotation.TransformVector(AZ::Vector3::CreateAxisY())); + const float axisDisplacementZ = action.LocalPositionOffset().Dot(localRotation.TransformVector(AZ::Vector3::CreateAxisZ())); + const float axisDisplacement = axisDisplacementZ > axisDisplacementY ? axisDisplacementZ : axisDisplacementY; + + const float originalBaseY = tan(AZ::DegToRad(sharedState->m_startValues.first)) * Internal::ConeHeight; + const float newBaseY = originalBaseY + axisDisplacement; + const float newAngleY = AZ::GetClamp(AZ::RadToDeg(atan(newBaseY / Internal::ConeHeight)), m_min, m_max); + + const float originalBaseZ = tan(AZ::DegToRad(sharedState->m_startValues.second)) * Internal::ConeHeight; + const float newBaseZ = originalBaseZ + axisDisplacement; + const float newAngleZ = AZ::GetClamp(AZ::RadToDeg(atan(newBaseZ / Internal::ConeHeight)), m_min, m_max); + + EditorJointRequestBus::Event( + m_entityComponentIdPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, + AngleLimitsFloatPair(newAngleY, newAngleZ)); + + m_yzPlanarManipulator->SetBoundsDirty(); + }); + + struct SharedStateXRotate + { + AZ::Transform m_startTM; + }; + auto sharedStateXRotate = AZStd::make_shared(); + + auto mouseDownCallback = [this, sharedRotationState](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + AZ::Quaternion normalizedStart = action.m_start.m_rotation.GetNormalized(); + sharedRotationState->m_axis = AZ::Vector3(normalizedStart.GetX(), normalizedStart.GetY(), normalizedStart.GetZ()); + sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); + + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult( + currentValue, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + sharedRotationState->m_valuePair = currentValue; + }; + + auto mouseDownRotateXCallback = + [this, sharedStateXRotate]([[maybe_unused]] const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + PhysX::EditorJointRequestBus::EventResult( + sharedStateXRotate->m_startTM, m_entityComponentIdPair, &PhysX::EditorJointRequests::GetTransformValue, + JointsComponentModeCommon::ParamaterNames::Transform); + }; + + m_xRotationManipulator->InstallLeftMouseDownCallback(mouseDownRotateXCallback); + + m_xRotationManipulator->InstallMouseMoveCallback( + [this, sharedStateXRotate](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; + + AZ::Transform newTransform = AZ::Transform::CreateIdentity(); + newTransform = sharedStateXRotate->m_startTM * AZ::Transform::CreateFromQuaternion(action.m_current.m_delta); + + PhysX::EditorJointRequestBus::Event( + m_entityComponentIdPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, + newTransform.GetTranslation()); + PhysX::EditorJointRequestBus::Event( + m_entityComponentIdPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation, + newTransform.GetRotation().GetEulerDegrees()); + + m_yLinearManipulator->SetLocalOrientation(manipulatorOrientation); + m_zLinearManipulator->SetLocalOrientation(manipulatorOrientation); + m_yLinearManipulator->SetAxis(action.m_current.m_delta.TransformVector(AZ::Vector3::CreateAxisY())); + m_zLinearManipulator->SetAxis(action.m_current.m_delta.TransformVector(AZ::Vector3::CreateAxisZ())); + m_xRotationManipulator->SetLocalOrientation(manipulatorOrientation); + + m_yLinearManipulator->SetBoundsDirty(); + m_zLinearManipulator->SetBoundsDirty(); + m_xRotationManipulator->SetBoundsDirty(); + }); + + m_xRotationManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + m_yLinearManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + m_zLinearManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + m_yzPlanarManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + + AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentIdPair.GetEntityId()); + + Refresh(m_entityComponentIdPair); + } + + void JointsSubComponentModeAngleCone::Refresh(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + float coneHeight = Internal::ConeHeight; + AngleLimitsFloatPair yzSwingAngleLimits; + EditorJointRequestBus::EventResult(yzSwingAngleLimits, idPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + // Draw inverted cone (negative cone height) if angles are larger than 90 deg. + if (yzSwingAngleLimits.first > 90.0f || yzSwingAngleLimits.second > 90.0f) + { + coneHeight = -Internal::ConeHeight; + } + + // reposition manipulators + const AZ::Quaternion localRotation = localTransform.GetRotation(); + const AZ::Vector3 linearManipulatorOffset = + localTransform.GetTranslation() + localRotation.TransformVector(AZ::Vector3(coneHeight, 0.0f, 0.0f)); + + m_xRotationManipulator->SetLocalTransform(localTransform); + + localTransform.SetTranslation(linearManipulatorOffset); + + m_yLinearManipulator->SetLocalTransform(localTransform); + m_zLinearManipulator->SetLocalTransform(localTransform); + m_yzPlanarManipulator->SetLocalTransform(localTransform); + } + + void JointsSubComponentModeAngleCone::Teardown(const AZ::EntityComponentIdPair& idPair) + { + AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); + + m_xRotationManipulator->RemoveEntityComponentIdPair(idPair); + m_xRotationManipulator->Unregister(); + m_yLinearManipulator->RemoveEntityComponentIdPair(idPair); + m_yLinearManipulator->Unregister(); + m_zLinearManipulator->RemoveEntityComponentIdPair(idPair); + m_zLinearManipulator->Unregister(); + m_yzPlanarManipulator->RemoveEntityComponentIdPair(idPair); + m_yzPlanarManipulator->Unregister(); + } + + void JointsSubComponentModeAngleCone::ResetValues(const AZ::EntityComponentIdPair& idPair) + { + EditorJointRequestBus::Event( + idPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, m_resetPostion); + EditorJointRequestBus::Event( + idPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation, m_resetRotation); + EditorJointRequestBus::Event(idPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, m_resetLimits); + } + + void JointsSubComponentModeAngleCone::ConfigureLinearView( + float axisLength, [[maybe_unused]] const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color) + { + const float coneLength = 0.28f; + const float coneRadius = 0.07f; + + const auto configureLinearView = + [coneLength, axisLength, coneRadius](AzToolsFramework::LinearManipulator* linearManipulator, const AZ::Color& color) + { + AzToolsFramework::ManipulatorViews views; + views.emplace_back(CreateManipulatorViewLine( + *linearManipulator, color, axisLength, + AzToolsFramework::ManipulatorLineBoundWidth(AzFramework::InvalidViewportId))); + views.emplace_back(CreateManipulatorViewCone( + *linearManipulator, color, linearManipulator->GetAxis() * (axisLength - coneLength), coneLength, coneRadius)); + linearManipulator->SetViews(AZStd::move(views)); + }; + + configureLinearView(m_yLinearManipulator.get(), axis2Color); + configureLinearView(m_zLinearManipulator.get(), axis3Color); + } + + void JointsSubComponentModeAngleCone::ConfigurePlanarView(const AZ::Color& planeColor, const AZ::Color& plane2Color) + { + const float planeSize = 0.6f; + AzToolsFramework::ManipulatorViews views; + views.emplace_back(CreateManipulatorViewQuad(*m_yzPlanarManipulator, planeColor, plane2Color, planeSize)); + m_yzPlanarManipulator->SetViews(AZStd::move(views)); + } + + void JointsSubComponentModeAngleCone::DisplayEntityViewport( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentIdPair.GetEntityId()); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, + JointsComponentModeCommon::ParamaterNames::Transform); + + AZ::u32 stateBefore = debugDisplay.GetState(); + debugDisplay.CullOff(); + + debugDisplay.PushMatrix(worldTransform); + debugDisplay.PushMatrix(localTransform); + + const float xAxisArrowLength = 2.0f; + debugDisplay.SetColor(AZ::Color(1.0f, 0.0f, 0.0f, 1.0f)); + debugDisplay.DrawArrow(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(xAxisArrowLength, 0.0f, 0.0f)); + + AngleLimitsFloatPair yzSwingAngleLimits; + EditorJointRequestBus::EventResult( + yzSwingAngleLimits, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + const AZ::u32 numEllipseSamples = 16; + AZ::Vector3 ellipseSamples[numEllipseSamples]; + float coneHeight = Internal::ConeHeight; + + // Draw inverted cone if angles are larger than 90 deg. + if (yzSwingAngleLimits.first > 90.0f || yzSwingAngleLimits.second > 90.0f) + { + coneHeight = -Internal::ConeHeight; + } + + // Compute points along perimeter of cone base + const float coney = tanf(AZ::DegToRad(yzSwingAngleLimits.first)) * coneHeight; + const float conez = tanf(AZ::DegToRad(yzSwingAngleLimits.second)) * coneHeight; + const float step = AZ::Constants::TwoPi / numEllipseSamples; + for (size_t i = 0; i < numEllipseSamples; ++i) + { + const float angleStep = step * i; + ellipseSamples[i].SetX(coneHeight); + ellipseSamples[i].SetY(conez * sin(angleStep)); + ellipseSamples[i].SetZ(coney * cos(angleStep)); + } + + // draw cone + for (size_t i = 0; i < numEllipseSamples; ++i) + { + size_t nextIndex = i + 1; + if (i == numEllipseSamples - 1) + { + nextIndex = 0; + } + + // draw cone sides + debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, 0.2f)); + debugDisplay.DrawTri(AZ::Vector3(0.0f, 0.0f, 0.0f), ellipseSamples[i], ellipseSamples[nextIndex]); + + // draw parameter of cone base + debugDisplay.SetColor(AZ::Color(0.4f, 0.4f, 0.4f, 0.4f)); + debugDisplay.DrawLine(ellipseSamples[i], ellipseSamples[nextIndex]); + } + + // draw axis lines at base of cone, and from tip to base. + debugDisplay.SetColor(AZ::Color(0.5f, 0.5f, 0.5f, 0.6f)); + debugDisplay.DrawLine(ellipseSamples[0], ellipseSamples[numEllipseSamples / 2]); + debugDisplay.DrawLine(ellipseSamples[numEllipseSamples * 3 / 4], ellipseSamples[numEllipseSamples / 4]); + debugDisplay.DrawLine(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(coneHeight, 0.0f, 0.0f)); + + debugDisplay.PopMatrix(); // pop local transform + debugDisplay.PopMatrix(); // pop world transform + debugDisplay.SetState(stateBefore); + + // reposition and reorientate manipulators + Refresh(m_entityComponentIdPair); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h new file mode 100644 index 0000000000..3f6d001112 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.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 + +#include +#include +#include +#include +#include +#include + +namespace AzToolsFramework +{ + class AngularManipulator; + class LinearManipulator; + class PlanarManipulator; +} // namespace AzToolsFramework + +namespace PhysX +{ + class JointsSubComponentModeAngleCone final + : public PhysXSubComponentModeBase + , private AzFramework::EntityDebugDisplayEventBus::Handler + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeAngleCone(const AZStd::string& propertyName, float max, float min); + + // PhysXSubComponentModeBase ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void Refresh(const AZ::EntityComponentIdPair& idPair) override; + void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + private: + void ConfigureLinearView( + float axisLength, + const AZ::Color& axis1Color, + const AZ::Color& axis2Color, + const AZ::Color& axis3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); + + void ConfigurePlanarView( + const AZ::Color& planeColor = AZ::Color(0.0f, 1.0f, 0.0f, 0.5f), + const AZ::Color& plane2Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); + + // AzFramework::EntityDebugDisplayEventBus + void DisplayEntityViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + float m_max = AZStd::numeric_limits::max(); + float m_min = -AZStd::numeric_limits::max(); + + AZ::EntityComponentIdPair m_entityComponentIdPair; + AZ::Vector3 m_resetPostion; + AZ::Vector3 m_resetRotation; + AngleLimitsFloatPair m_resetLimits; + AZStd::string m_propertyName; + AZStd::shared_ptr m_xRotationManipulator; + AZStd::shared_ptr m_yLinearManipulator; + AZStd::shared_ptr m_zLinearManipulator; + AZStd::shared_ptr m_yzPlanarManipulator; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.cpp new file mode 100644 index 0000000000..84b0cd4b5b --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.cpp @@ -0,0 +1,305 @@ +/* + * 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 + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeAnglePair, AZ::SystemAllocator, 0); + + namespace Internal + { + const float Alpha = 0.6f; + const AZ::Color ColorDefault = AZ::Color(1.0f, 1.0f, 1.0f, Alpha); + const AZ::Color ColorFirst = AZ::Color(1.0f, 0.0f, 0.0f, Alpha); + const AZ::Color ColorSecond = AZ::Color(0.0f, 1.0f, 0.0f, Alpha); + const AZ::Color ColorSweepArc = AZ::Color(1.0f, 1.0f, 1.0f, Alpha); + + const float SweepLineDisplaceFactor = 0.5f; + const float SweepLineThickness = 1.0f; + const float SweepLineGranularity = 1.0f; + } // namespace Internal + + JointsSubComponentModeAnglePair::JointsSubComponentModeAnglePair( + const AZStd::string& propertyName, const AZ::Vector3& axis, float max, float min) + : m_propertyName(propertyName) + , m_axis(axis) + , m_firstMax(max) + , m_firstMin(min) + , m_secondMax(min) + , m_secondMin(-max) + { + + } + + void JointsSubComponentModeAnglePair::Setup(const AZ::EntityComponentIdPair& idPair) + { + m_entityComponentIdPair = idPair; + EditorJointRequestBus::EventResult(m_resetValue, idPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + const AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(idPair.GetEntityId()); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + const AZ::Quaternion localRotation = localTransform.GetRotation(); + + AZ::Vector3 displacement = m_axis; + AZ::Transform displacementTransform = localTransform; + AZ::Vector3 displacementTranslate = localRotation.TransformVector(displacement); + displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); + + m_firstManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); + m_firstManipulator->AddEntityComponentIdPair(idPair); + m_firstManipulator->SetAxis(m_axis); + m_firstManipulator->SetLocalTransform(displacementTransform); + + displacement = -m_axis; + displacementTranslate = localRotation.TransformVector(displacement); + displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); + m_secondManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); + m_secondManipulator->AddEntityComponentIdPair(idPair); + m_secondManipulator->SetAxis(m_axis); + m_secondManipulator->SetLocalTransform(displacementTransform); + + const float manipulatorRadius = 2.0f; + const float manipulatorWidth = 0.05f; + m_firstManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( + *m_firstManipulator, Internal::ColorFirst, manipulatorRadius, manipulatorWidth, AzToolsFramework::DrawHalfDottedCircle)); + + m_secondManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( + *m_secondManipulator, Internal::ColorSecond, manipulatorRadius, manipulatorWidth, AzToolsFramework::DrawHalfDottedCircle)); + + Refresh(idPair); + + m_sharedRotationState = AZStd::make_shared(); + + auto mouseDownCallback = [this, + idPair](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + const AZ::Quaternion normalizedStart = action.m_start.m_rotation.GetNormalized(); + m_sharedRotationState->m_axis = AZ::Vector3(normalizedStart.GetX(), normalizedStart.GetY(), normalizedStart.GetZ()); + m_sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); + + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult(currentValue, idPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + m_sharedRotationState->m_valuePair = currentValue; + }; + + m_firstManipulator->InstallLeftMouseDownCallback(mouseDownCallback); + + m_secondManipulator->InstallLeftMouseDownCallback(mouseDownCallback); + + m_firstManipulator->InstallMouseMoveCallback( + [this, idPair](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + float angleDelta; + AZ::Quaternion manipulatorOrientation; + const float newValue = MouseMove(m_sharedRotationState, action, true, angleDelta, manipulatorOrientation); + if (newValue > m_firstMax || newValue < m_firstMin) + { + return; + } + m_firstManipulator->SetLocalOrientation(manipulatorOrientation); + const float newFirstValue = AZ::GetClamp(m_sharedRotationState->m_valuePair.first + angleDelta, m_firstMin, m_firstMax); + + EditorJointRequestBus::Event( + idPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, + AngleLimitsFloatPair(newFirstValue, m_sharedRotationState->m_valuePair.second)); + }); + + m_secondManipulator->InstallMouseMoveCallback( + [this, idPair](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + float angleDelta; + AZ::Quaternion manipulatorOrientation; + const float newValue = MouseMove(m_sharedRotationState, action, false, angleDelta, manipulatorOrientation); + if (newValue > m_secondMax || newValue < m_secondMin) + { + return; // Not handling values exceeding limits + } + + m_secondManipulator->SetLocalOrientation(manipulatorOrientation); + float newSecondValue = AZ::GetClamp(m_sharedRotationState->m_valuePair.second + angleDelta, m_secondMin, m_secondMax); + + EditorJointRequestBus::Event( + idPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, + AngleLimitsFloatPair(m_sharedRotationState->m_valuePair.first, newSecondValue)); + }); + + m_firstManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + m_secondManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + + AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(idPair.GetEntityId()); + } + + void JointsSubComponentModeAnglePair::Refresh(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + const AZ::Quaternion localRotation = localTransform.GetRotation(); + + AZ::Transform displacementTransform = localTransform; + AZ::Vector3 displacement = m_axis; + AZ::Vector3 displacementTranslate = localRotation.TransformVector(displacement); + displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); + m_firstManipulator->SetLocalTransform(displacementTransform); + + displacement = -m_axis; + displacementTranslate = localRotation.TransformVector(displacement); + displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); + m_secondManipulator->SetLocalTransform(displacementTransform); + } + + void JointsSubComponentModeAnglePair::Teardown(const AZ::EntityComponentIdPair& idPair) + { + AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); + m_firstManipulator->RemoveEntityComponentIdPair(idPair); + m_firstManipulator->Unregister(); + m_secondManipulator->RemoveEntityComponentIdPair(idPair); + m_secondManipulator->Unregister(); + } + + void JointsSubComponentModeAnglePair::ResetValues(const AZ::EntityComponentIdPair& idPair) + { + EditorJointRequestBus::Event(idPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, m_resetValue); + + m_firstManipulator->SetLocalOrientation(AZ::Quaternion::CreateFromAxisAngle(m_axis, m_resetValue.first)); + m_secondManipulator->SetLocalOrientation(AZ::Quaternion::CreateFromAxisAngle(m_axis, m_resetValue.first)); + } + + float JointsSubComponentModeAnglePair::MouseMove( + AZStd::shared_ptr& sharedRotationState, + const AzToolsFramework::AngularManipulator::Action& action, + bool isFirstValue, + float& angleDelta, + AZ::Quaternion& manipulatorOrientation) + { + sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull(); + angleDelta = 0.0f; + AZ::Vector3 axis = m_axis; + sharedRotationState->m_savedOrientation.ConvertToAxisAngle(axis, angleDelta); + // Polarity of axis is switched by ConvertToAxisAngle call depending on direction of rotation + if (abs(m_axis.GetX() - 1.0f) < FLT_EPSILON) + { + angleDelta = AZ::RadToDeg(angleDelta) * axis.GetX(); + } + else if (abs(m_axis.GetY() - 1.0f) < FLT_EPSILON) + { + angleDelta = AZ::RadToDeg(angleDelta) * axis.GetY(); + } + else if (abs(m_axis.GetZ() - 1.0f) < FLT_EPSILON) + { + angleDelta = AZ::RadToDeg(angleDelta) * axis.GetZ(); + } + + manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; + + if (isFirstValue) + { + return sharedRotationState->m_valuePair.first + angleDelta; + } + return sharedRotationState->m_valuePair.second + angleDelta; + } + + void JointsSubComponentModeAnglePair::DisplayEntityViewport( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult(currentValue, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + const float size = 2.0f; + AZ::Vector3 axisPoint = m_axis * size * 0.5f; + + AZStd::array points = { -axisPoint, axisPoint, axisPoint, -axisPoint }; + + if (abs(m_axis.GetX() - 1.0f) < FLT_EPSILON) + { + points[2].SetZ(size); + points[3].SetZ(size); + } + else if (abs(m_axis.GetY() - 1.0f) < FLT_EPSILON) + { + points[2].SetX(size); + points[3].SetX(size); + } + else if (abs(m_axis.GetZ() - 1.0f) < FLT_EPSILON) + { + points[2].SetX(size); + points[3].SetX(size); + } + + AZ::u32 stateBefore = debugDisplay.GetState(); + debugDisplay.CullOff(); + debugDisplay.SetAlpha(Internal::Alpha); + + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentIdPair.GetEntityId()); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + debugDisplay.PushMatrix(worldTransform); + debugDisplay.PushMatrix(localTransform); + + debugDisplay.SetColor(Internal::ColorSweepArc); + + const AZ::Vector3 zeroVector = AZ::Vector3::CreateZero(); + const AZ::Vector3 posPosition = m_axis * Internal::SweepLineDisplaceFactor; + const AZ::Vector3 negPosition = -posPosition; + debugDisplay.DrawArc( + posPosition, Internal::SweepLineThickness, -currentValue.first, currentValue.first, Internal::SweepLineGranularity, -m_axis); + debugDisplay.DrawArc( + zeroVector, Internal::SweepLineThickness, -currentValue.first, currentValue.first, Internal::SweepLineGranularity, -m_axis); + debugDisplay.DrawArc( + negPosition, Internal::SweepLineThickness, -currentValue.first, currentValue.first, Internal::SweepLineGranularity, -m_axis); + debugDisplay.DrawArc( + posPosition, Internal::SweepLineThickness, 0.0f, abs(currentValue.second), Internal::SweepLineGranularity, -m_axis); + debugDisplay.DrawArc( + zeroVector, Internal::SweepLineThickness, 0.0f, abs(currentValue.second), Internal::SweepLineGranularity, -m_axis); + debugDisplay.DrawArc( + negPosition, Internal::SweepLineThickness, 0.0f, abs(currentValue.second), Internal::SweepLineGranularity, -m_axis); + + AZ::Quaternion firstRotate = AZ::Quaternion::CreateFromAxisAngle(m_axis, AZ::DegToRad(currentValue.first)); + AZ::Transform firstTM = AZ::Transform::CreateFromQuaternion(firstRotate); + debugDisplay.PushMatrix(firstTM); + debugDisplay.SetColor(Internal::ColorFirst); + debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); + debugDisplay.PopMatrix(); + + AZ::Quaternion secondRotate = AZ::Quaternion::CreateFromAxisAngle(m_axis, AZ::DegToRad(currentValue.second)); + AZ::Transform secondTM = AZ::Transform::CreateFromQuaternion(secondRotate); + debugDisplay.PushMatrix(secondTM); + debugDisplay.SetColor(Internal::ColorSecond); + debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); + debugDisplay.PopMatrix(); + + debugDisplay.SetColor(Internal::ColorDefault); + debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); + + debugDisplay.PopMatrix(); // pop local transform + debugDisplay.PopMatrix(); // pop global transform + debugDisplay.SetState(stateBefore); + + // reposition and reorientate manipulators + Refresh(m_entityComponentIdPair); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.h new file mode 100644 index 0000000000..b50a16bf77 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.h @@ -0,0 +1,70 @@ +/* + * 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 AZ +{ + class Vector3; +} // namespace AZ + +namespace PhysX +{ + namespace AngleComponentModes + { + struct SharedRotationState; + } // namespace AngleComponentModes + + class JointsSubComponentModeAnglePair final + : public PhysXSubComponentModeBase + , private AzFramework::EntityDebugDisplayEventBus::Handler + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeAnglePair(const AZStd::string& propertyName, const AZ::Vector3& axis, float max, float min); + + // PhysXSubComponentModeBase ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void Refresh(const AZ::EntityComponentIdPair& idPair) override; + void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + private: + float MouseMove( + AZStd::shared_ptr& sharedRotationState, + const AzToolsFramework::AngularManipulator::Action& action, + bool isFirstValue, + float& angleDelta, + AZ::Quaternion& manipulatorOrientation); + + // AzFramework::EntityDebugDisplayEventBus + void DisplayEntityViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); + float m_firstMax = AZStd::numeric_limits::max(); + float m_firstMin = -AZStd::numeric_limits::max(); + float m_secondMax = AZStd::numeric_limits::max(); + float m_secondMin = -AZStd::numeric_limits::max(); + AZStd::shared_ptr m_sharedRotationState; + AngleLimitsFloatPair m_resetValue; + AZ::EntityComponentIdPair m_entityComponentIdPair; + + AZStd::string m_propertyName; + AZStd::shared_ptr m_firstManipulator; + AZStd::shared_ptr m_secondManipulator; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.cpp new file mode 100644 index 0000000000..ec073b49ef --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.cpp @@ -0,0 +1,133 @@ +/* + * 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 + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeLinearFloat, AZ::SystemAllocator, 0); + + JointsSubComponentModeLinearFloat::JointsSubComponentModeLinearFloat( + const AZStd::string& propertyName, float exponent, float max, float min) + : m_propertyName(propertyName) + , m_exponent(exponent) + , m_inverseExponent(1.0f / exponent) + , m_max(max) + , m_min(min) + { + + } + + void JointsSubComponentModeLinearFloat::Setup(const AZ::EntityComponentIdPair& idPair) + { + EditorJointRequestBus::EventResult(m_resetValue, idPair, &EditorJointRequests::GetLinearValue, m_propertyName); + + const AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(idPair.GetEntityId()); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + m_manipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); + m_manipulator->AddEntityComponentIdPair(idPair); + m_manipulator->SetAxis(AZ::Vector3::CreateAxisX()); + m_manipulator->SetLocalTransform(localTransform); + + Refresh(idPair); + + const AZ::Color manipulatorColor(0.3f, 0.3f, 0.3f, 1.0f); + const float manipulatorSize = 0.05f; + + AzToolsFramework::ManipulatorViews views; + views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(manipulatorColor, manipulatorSize)); + m_manipulator->SetViews(AZStd::move(views)); + + struct SharedState + { + float m_startingValue = 0.0f; + }; + auto sharedState = AZStd::make_shared(); + + m_manipulator->InstallLeftMouseDownCallback( + [this, sharedState, idPair]([[maybe_unused]]const AzToolsFramework::LinearManipulator::Action& action) mutable + { + float currentValue = 0.0f; + + EditorJointRequestBus::EventResult(currentValue, idPair, &EditorJointRequests::GetLinearValue, m_propertyName); + sharedState->m_startingValue = currentValue; + }); + + m_manipulator->InstallMouseMoveCallback( + [this, sharedState, idPair](const AzToolsFramework::LinearManipulator::Action& action) + { + const float axisDisplacement = action.LocalPositionOffset().Dot(action.m_fixed.m_axis); + + float newValue = AZ::GetClamp(sharedState->m_startingValue + DisplacementToDeltaValue(axisDisplacement), m_min, m_max); + EditorJointRequestBus::Event(idPair, &EditorJointRequests::SetLinearValue, m_propertyName, newValue); + + const AZ::Vector3 localPosition = action.LocalPosition().GetMax(AZ::Vector3(0.01f, 0.0f, 0.0f)); + m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(localPosition)); + }); + + m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + } + + void JointsSubComponentModeLinearFloat::Refresh(const AZ::EntityComponentIdPair& idPair) + { + float currentValue = 0.0f; + EditorJointRequestBus::EventResult(currentValue, idPair, &EditorJointRequests::GetLinearValue, m_propertyName); + + m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX() * ValueToDisplacement(currentValue))); + } + + void JointsSubComponentModeLinearFloat::Teardown(const AZ::EntityComponentIdPair& idPair) + { + m_manipulator->RemoveEntityComponentIdPair(idPair); + m_manipulator->Unregister(); + m_manipulator.reset(); + } + + void JointsSubComponentModeLinearFloat::ResetValues(const AZ::EntityComponentIdPair& idPair) + { + EditorJointRequestBus::Event(idPair, &EditorJointRequests::SetLinearValue, m_propertyName, m_resetValue); + m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX() * ValueToDisplacement(m_resetValue))); + } + + float JointsSubComponentModeLinearFloat::DisplacementToDeltaValue(float displacement) const + { + if (displacement > 0.0f) + { + return AZStd::pow(displacement, m_exponent); + } + else if (displacement < 0.0f) + { + return -AZStd::pow(fabsf(displacement), m_exponent); + } + else + { + return 0.0f; + } + } + + float JointsSubComponentModeLinearFloat::ValueToDisplacement(float value) const + { + return AZStd::pow(value, m_inverseExponent); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.h new file mode 100644 index 0000000000..d65e59d081 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.h @@ -0,0 +1,56 @@ +/* + * 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 + +namespace AZ +{ + class Vector3; +} // namespace AZ + +namespace AzToolsFramework +{ + class LinearManipulator; +} // namespace AzToolsFramework + +namespace PhysX +{ + class JointsSubComponentModeLinearFloat final + : public PhysXSubComponentModeBase + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeLinearFloat( + const AZStd::string& propertyName, float exponent, float max, float min); + + // PhysXSubComponentModeBase ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void Refresh(const AZ::EntityComponentIdPair& idPair) override; + void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + private: + float DisplacementToDeltaValue(float displacement) const; + float ValueToDisplacement(float value) const; + + float m_exponent = 1.0f; + float m_inverseExponent = 1.0f; + float m_max = AZStd::numeric_limits::max(); + float m_min = -AZStd::numeric_limits::max(); + float m_resetValue = 0.0f; + AZStd::string m_propertyName; + AZStd::shared_ptr m_manipulator; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.cpp new file mode 100644 index 0000000000..2bca1700e5 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.cpp @@ -0,0 +1,134 @@ +/* + * 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 +#include + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeRotation, AZ::SystemAllocator, 0); + + void JointsSubComponentModeRotation::Setup(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(idPair.GetEntityId()); + + const AZ::Quaternion worldRotation = worldTransform.GetRotation(); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + EditorJointRequestBus::EventResult( + m_resetValue, idPair, &PhysX::EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation); + + const AZStd::array axes = { AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ() }; + + const AZStd::array colors = { AZ::Color(1.0f, 0.0f, 0.0f, 1.0f), AZ::Color(0.0f, 1.0f, 0.0f, 1.0f), + AZ::Color(0.0f, 0.0f, 1.0f, 1.0f) }; + + for (AZ::u32 i = 0; i < 3; ++i) + { + m_manipulators[i] = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); + m_manipulators[i]->AddEntityComponentIdPair(idPair); + m_manipulators[i]->SetAxis(axes[i]); + m_manipulators[i]->SetLocalTransform(localTransform); + const float manipulatorRadius = 2.0f; + m_manipulators[i]->SetView(AzToolsFramework::CreateManipulatorViewCircle( + *m_manipulators[i], colors[i], manipulatorRadius, + AzToolsFramework::ManipulatorCicleBoundWidth(), AzToolsFramework::DrawHalfDottedCircle)); + + m_manipulators[i]->Register(AzToolsFramework::g_mainManipulatorManagerId); + } + InstallManipulatorMouseCallbacks(idPair); + } + + void JointsSubComponentModeRotation::Refresh(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + for (auto rotationManipulator : m_manipulators) + { + rotationManipulator->SetLocalTransform(localTransform); + } + } + + void JointsSubComponentModeRotation::Teardown(const AZ::EntityComponentIdPair& idPair) + { + for (auto rotationManipulator : m_manipulators) + { + rotationManipulator->RemoveEntityComponentIdPair(idPair); + rotationManipulator->Unregister(); + } + } + + void JointsSubComponentModeRotation::ResetValues(const AZ::EntityComponentIdPair& idPair) + { + EditorJointRequestBus::Event( + idPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation, m_resetValue); + + const AZ::Quaternion reset = AZ::Quaternion::CreateFromEulerAnglesDegrees(m_resetValue); + for (auto manipulator : m_manipulators) + { + manipulator->SetLocalOrientation(reset); + } + } + + void JointsSubComponentModeRotation::InstallManipulatorMouseCallbacks(const AZ::EntityComponentIdPair& idPair) + { + struct SharedState + { + AZ::Transform m_startTM; + }; + auto sharedState = AZStd::make_shared(); + + auto mouseDownRotateXCallback = + [sharedState, idPair]([[maybe_unused]] const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + EditorJointRequestBus::EventResult( + sharedState->m_startTM, idPair, &PhysX::EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + }; + + for (AZ::u32 index = 0; index < 3; ++index) + { + m_manipulators[index]->InstallLeftMouseDownCallback(mouseDownRotateXCallback); + + m_manipulators[index]->InstallMouseMoveCallback( + [this, index, sharedState, idPair](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; + + AZ::Transform newTransform = AZ::Transform::CreateIdentity(); + newTransform = sharedState->m_startTM * AZ::Transform::CreateFromQuaternion(action.m_current.m_delta); + + EditorJointRequestBus::Event( + idPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation, + newTransform.GetRotation().GetEulerDegrees()); + + m_manipulators[index]->SetLocalOrientation(manipulatorOrientation); + }); + } + } +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.h new file mode 100644 index 0000000000..a9a1888dd0 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.h @@ -0,0 +1,44 @@ +/* + * 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 + +namespace AzToolsFramework +{ + class AngularManipulator; +} + +namespace PhysX +{ + class JointsSubComponentModeRotation final + : public PhysXSubComponentModeBase + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeRotation() = default; + + // PhysXSubComponentModeBase ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void Refresh(const AZ::EntityComponentIdPair& idPair) override; + void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + private: + void InstallManipulatorMouseCallbacks(const AZ::EntityComponentIdPair& idPair); + + AZ::Vector3 m_resetValue = AZ::Vector3::CreateZero(); + AZStd::array, 3> m_manipulators; + }; +} diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.cpp similarity index 71% rename from Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.cpp rename to Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.cpp index 5220b2e274..0f3467eb54 100644 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.cpp +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.cpp @@ -1,4 +1,3 @@ - /* * 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. @@ -6,49 +5,67 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include -#include +#include + +#include #include +#include #include -#include -#include +#include #include #include namespace PhysX { - EditorSubComponentModeSnap::EditorSubComponentModeSnap( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeSnap, AZ::SystemAllocator, 0); + + void JointsSubComponentModeSnap::Setup(const AZ::EntityComponentIdPair& idPair) { + m_entityComponentId = idPair; + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); AZ::Transform localTransform = AZ::Transform::CreateIdentity(); EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); + localTransform, m_entityComponentId, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); m_manipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); m_manipulator->AddEntityComponentIdPair(m_entityComponentId); m_manipulator->SetAxis(AZ::Vector3::CreateAxisX()); m_manipulator->SetLocalTransform(localTransform); - Refresh(); + Refresh(idPair); const AZ::Color manipulatorColor(0.3f, 0.3f, 0.3f, 1.0f); const float manipulatorSize = 0.05f; AzToolsFramework::ManipulatorViews views; - views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(manipulatorColor - , manipulatorSize)); + views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(manipulatorColor, manipulatorSize)); m_manipulator->SetViews(AZStd::move(views)); + + m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); } - void EditorSubComponentModeSnap::HandleMouseInteraction( - const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) + void JointsSubComponentModeSnap::Refresh(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + m_manipulator->SetLocalTransform(localTransform); + } + + void JointsSubComponentModeSnap::Teardown(const AZ::EntityComponentIdPair& idPair) + { + AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); + + m_manipulator->RemoveEntityComponentIdPair(idPair); + m_manipulator->Unregister(); + m_manipulator.reset(); + } + + void JointsSubComponentModeSnap::HandleMouseInteraction(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) { if (mouseInteraction.m_mouseEvent == AzToolsFramework::ViewportInteraction::MouseEvent::Move) { @@ -63,25 +80,36 @@ namespace PhysX const AZ::Quaternion worldRotateInv = worldRotate.GetInverseFull(); m_manipulator->SetLocalPosition(worldRotateInv.TransformVector(m_pickedPosition - worldTransform.GetTranslation())); - m_manipulator->SetBoundsDirty(); } } } - void EditorSubComponentModeSnap::Refresh() + AZStd::string JointsSubComponentModeSnap::GetPickedEntityName() { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - m_manipulator->SetLocalTransform(localTransform); + AZStd::string pickedEntityName; + if (m_pickedEntity.IsValid()) + { + AZ::ComponentApplicationBus::BroadcastResult( + pickedEntityName, &AZ::ComponentApplicationRequests::GetEntityName, m_pickedEntity); + } + return pickedEntityName; } - void EditorSubComponentModeSnap::DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + AZ::Vector3 JointsSubComponentModeSnap::GetPosition() const + { + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); + + AZ::Quaternion worldRotate = worldTransform.GetRotation(); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentId, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + return worldTransform.GetTranslation() + worldRotate.TransformVector(localTransform.GetTranslation()); + } + + void JointsSubComponentModeSnap::DisplayEntityViewport( + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { AZ::u32 stateBefore = debugDisplay.GetState(); @@ -89,11 +117,9 @@ namespace PhysX AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - AZ::Transform localTransform = AZ::Transform::CreateIdentity();; + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); + localTransform, m_entityComponentId, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); debugDisplay.PushMatrix(worldTransform); debugDisplay.PushMatrix(localTransform); @@ -104,9 +130,7 @@ namespace PhysX AngleLimitsFloatPair yzSwingAngleLimits; EditorJointRequestBus::EventResult( - yzSwingAngleLimits, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , PhysX::EditorJointComponentMode::s_parameterSwingLimit); + yzSwingAngleLimits, m_entityComponentId, &EditorJointRequests::GetLinearValuePair, JointsComponentModeCommon::ParamaterNames::SwingLimit); const AZ::u32 numEllipseSamples = 16; AZStd::array ellipseSamples; @@ -154,8 +178,8 @@ namespace PhysX debugDisplay.DrawLine(ellipseSamples[numEllipseSamples * 3 / 4], ellipseSamples[numEllipseSamples / 4]); debugDisplay.DrawLine(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(coneHeight, 0.0f, 0.0f)); - debugDisplay.PopMatrix();//pop local transform - debugDisplay.PopMatrix();//pop world transform + debugDisplay.PopMatrix(); // pop local transform + debugDisplay.PopMatrix(); // pop world transform // draw line from joint to mouse-over entity if (m_pickedEntity.IsValid()) @@ -173,40 +197,9 @@ namespace PhysX debugDisplay.DrawWireBox(m_pickedEntityAabb.GetMin(), m_pickedEntityAabb.GetMax()); // draw something, e.g. an icon, to indicate type of snapping - DisplaySpecificSnapType(viewportInfo, - debugDisplay, - position, - directionNorm, - directionLength); + DisplaySpecificSnapType(viewportInfo, debugDisplay, position, directionNorm, directionLength); } debugDisplay.SetState(stateBefore); } - - AZStd::string EditorSubComponentModeSnap::GetPickedEntityName() - { - AZStd::string pickedEntityName; - if (m_pickedEntity.IsValid()) - { - AZ::ComponentApplicationBus::BroadcastResult(pickedEntityName, - &AZ::ComponentApplicationRequests::GetEntityName, - m_pickedEntity); - } - return pickedEntityName; - } - - AZ::Vector3 EditorSubComponentModeSnap::GetPosition() const - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Quaternion worldRotate = worldTransform.GetRotation(); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - return worldTransform.GetTranslation() + worldRotate.TransformVector(localTransform.GetTranslation()); - } } // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h similarity index 51% rename from Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.h rename to Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h index 585d46c2b6..843fffd4c8 100644 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.h +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h @@ -1,4 +1,3 @@ - /* * 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. @@ -6,12 +5,16 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once +#include +#include +#include #include -#include #include +#include namespace AzToolsFramework { @@ -20,48 +23,43 @@ namespace AzToolsFramework namespace PhysX { - /// This sub-component mode uses EditorViewportEntityPicker to get the position of an entity that the mouse is hovering over. - /// Classes inheriting from this class can use the mouse-over entity position to perform custom actions. - class EditorSubComponentModeSnap - : public PhysX::EditorSubComponentModeBase + class JointsSubComponentModeSnap + : public PhysXSubComponentModeBase , protected AzFramework::EntityDebugDisplayEventBus::Handler { public: - EditorSubComponentModeSnap( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name); - virtual ~EditorSubComponentModeSnap() = default; + AZ_CLASS_ALLOCATOR_DECL; - // PhysX::EditorSubComponentModeBase - void HandleMouseInteraction( - const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; - void Refresh() override; + JointsSubComponentModeSnap() = default; + + // PhysXSubComponentModeBase ... + virtual void Setup(const AZ::EntityComponentIdPair& idPair) override; + virtual void Refresh(const AZ::EntityComponentIdPair& idPair) override; + virtual void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void HandleMouseInteraction(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; protected: - // AzFramework::EntityDebugDisplayEventBus - void DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; + AZStd::string GetPickedEntityName(); + AZ::Vector3 GetPosition() const; - /// Override to draw specific snap type display + // AzFramework::EntityDebugDisplayEventBus + void DisplayEntityViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + //! Override to draw specific snap type display virtual void DisplaySpecificSnapType( [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, [[maybe_unused]] AzFramework::DebugDisplayRequests& debugDisplay, [[maybe_unused]] const AZ::Vector3& jointPosition, [[maybe_unused]] const AZ::Vector3& snapDirection, - [[maybe_unused]] float snapLength) {} - - virtual void InitMouseDownCallBack() = 0; - - AZStd::string GetPickedEntityName(); - AZ::Vector3 GetPosition() const; - - AZStd::shared_ptr m_manipulator; + [[maybe_unused]] float snapLength) + { + } EditorViewportEntityPicker m_picker; AZ::EntityId m_pickedEntity; AZ::Aabb m_pickedEntityAabb = AZ::Aabb::CreateNull(); AZ::Vector3 m_pickedPosition; + AZ::EntityComponentIdPair m_entityComponentId; + AZStd::shared_ptr m_manipulator; }; -} // namespace PhysX +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.cpp new file mode 100644 index 0000000000..809ccd97cb --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.cpp @@ -0,0 +1,91 @@ +/* + * 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 PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeSnapPosition, AZ::SystemAllocator, 0); + + void JointsSubComponentModeSnapPosition::Setup(const AZ::EntityComponentIdPair& idPair) + { + JointsSubComponentModeSnap::Setup(idPair); + + PhysX::EditorJointRequestBus::EventResult( + m_resetPosition, m_entityComponentId, &PhysX::EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Position); + + PhysX::EditorJointRequestBus::EventResult( + m_resetLeadEntity, m_entityComponentId, &PhysX::EditorJointRequests::GetEntityIdValue, + JointsComponentModeCommon::ParamaterNames::LeadEntity); + + m_manipulator->InstallLeftMouseDownCallback( + [this](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable + { + if (!m_pickedEntity.IsValid()) + { + return; + } + + const AZ::Vector3 newLocalPosition = PhysX::Utils::ComputeJointLocalTransform( + PhysX::Utils::GetEntityWorldTransformWithScale(m_pickedEntity), + PhysX::Utils::GetEntityWorldTransformWithScale(m_entityComponentId.GetEntityId())) + .GetTranslation(); + + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, + newLocalPosition); + + const bool selectedEntityIsNotJointEntity = m_pickedEntity != m_entityComponentId.GetEntityId(); + + AZ_Error( + "EditorSubComponentModeSnapPosition", selectedEntityIsNotJointEntity, + "Joint's lead entity cannot be the same as the entity in which the joint resides. Select lead entity on snap failed."); + + if (selectedEntityIsNotJointEntity) + { + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetEntityIdValue, JointsComponentModeCommon::ParamaterNames::LeadEntity, + m_pickedEntity); + } + }); + } + + void JointsSubComponentModeSnapPosition::ResetValues([[maybe_unused]]const AZ::EntityComponentIdPair& idPair) + { + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, m_resetPosition); + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetEntityIdValue, JointsComponentModeCommon::ParamaterNames::LeadEntity, m_resetLeadEntity); + } + + void JointsSubComponentModeSnapPosition::DisplaySpecificSnapType( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay, + const AZ::Vector3& jointPosition, + const AZ::Vector3& snapDirection, + float snapLength) + { + const float arrowLength = 1.0f; + const float iconGap = 1.0f; + const AZ::Vector3 iconPosition = jointPosition + (snapDirection * (snapLength + arrowLength + iconGap)); + + debugDisplay.SetColor(AZ::Colors::Red); + debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(arrowLength, 0.0f, 0.0f)); + debugDisplay.SetColor(AZ::Colors::Green); + debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(0.2f, arrowLength, 0.2f)); + debugDisplay.SetColor(AZ::Colors::Blue); + debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(0.0f, 0.0f, arrowLength)); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.h new file mode 100644 index 0000000000..c762db54d2 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.h @@ -0,0 +1,42 @@ +/* + * 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 PhysX +{ + class JointsSubComponentModeSnapPosition final + : public JointsSubComponentModeSnap + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeSnapPosition() = default; + + // JointsSubComponentModeSnap ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + protected: + // JointsSubComponentModeSnap ... + void DisplaySpecificSnapType( + const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay, + const AZ::Vector3& jointPosition, + const AZ::Vector3& snapDirection, + float snapLength) override; + + private: + AZ::Vector3 m_resetPosition; + AZ::EntityId m_resetLeadEntity; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.cpp new file mode 100644 index 0000000000..7d48bf7772 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.cpp @@ -0,0 +1,117 @@ +/* + * 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 + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeSnapRotation, AZ::SystemAllocator, 0); + + void JointsSubComponentModeSnapRotation::Setup(const AZ::EntityComponentIdPair& idPair) + { + JointsSubComponentModeSnap::Setup(idPair); + + PhysX::EditorJointRequestBus::EventResult( + m_resetRotation, m_entityComponentId, &PhysX::EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation); + + m_manipulator->InstallLeftMouseDownCallback( + [this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action) mutable + { + if (!m_pickedEntity.IsValid()) + { + return; + } + + AZ::EntityId leadEntityId; + PhysX::EditorJointRequestBus::EventResult( + leadEntityId, m_entityComponentId, &PhysX::EditorJointRequests::GetEntityIdValue, + JointsComponentModeCommon::ParamaterNames::LeadEntity); + + if (leadEntityId.IsValid() && m_pickedEntity == leadEntityId) + { + AZ_Warning( + "EditorsubComponentModeSnapRotation", false, + "The entity %s is the lead of the joint. Please snap rotation (or orientation) of joint to another entity that is " + "not the lead entity.", + GetPickedEntityName().c_str()); + return; + } + + AZ::Transform worldTransform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(worldTransform, m_entityComponentId.GetEntityId(), &AZ::TransformInterface::GetWorldTM); + worldTransform.ExtractUniformScale(); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentId, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + AZ::Transform pickedEntityTransform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(pickedEntityTransform, m_pickedEntity, &AZ::TransformInterface::GetWorldTM); + + const AZ::Transform worldTransformInv = worldTransform.GetInverse(); + const AZ::Vector3 pickedLocalPosition = + worldTransformInv.TransformVector(pickedEntityTransform.GetTranslation()) - localTransform.GetTranslation(); + + if (AZStd::abs(pickedLocalPosition.GetLength()) < FLT_EPSILON) + { + AZ_Warning( + "EditorsubComponentModeSnapRotation", false, + "The entity %s is too close to the joint position. Please snap rotation to an entity that is not at the position " + "of the joint.", + GetPickedEntityName().c_str()); + return; + } + + const AZ::Vector3 targetDirection = pickedLocalPosition.GetNormalized(); + const AZ::Vector3 sourceDirection = AZ::Vector3::CreateAxisX(); + const AZ::Quaternion newLocalRotation = AZ::Quaternion::CreateShortestArc(sourceDirection, targetDirection); + + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetVector3Value, + JointsComponentModeCommon::ParamaterNames::Rotation // using rotation parameter name to set the local rotation value + , + newLocalRotation.GetEulerDegrees()); + }); + } + + void JointsSubComponentModeSnapRotation::ResetValues([[maybe_unused]] const AZ::EntityComponentIdPair& idPair) + { + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation, m_resetRotation); + } + + void JointsSubComponentModeSnapRotation::DisplaySpecificSnapType( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay, + const AZ::Vector3& jointPosition, + const AZ::Vector3& snapDirection, + float snapLength) + { + const float circleRadius = 0.5f; + const float iconGap = 1.0f; + + const AZ::Vector3 iconPosition = jointPosition + (snapDirection * (snapLength + circleRadius * 2.0f + iconGap)); + + debugDisplay.SetColor(AZ::Colors::Red); + debugDisplay.DrawCircle(iconPosition, circleRadius, 0); + debugDisplay.SetColor(AZ::Colors::Green); + debugDisplay.DrawCircle(iconPosition, circleRadius, 1); + debugDisplay.SetColor(AZ::Colors::Blue); + debugDisplay.DrawCircle(iconPosition, circleRadius, 2); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.h new file mode 100644 index 0000000000..d8aa613684 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.h @@ -0,0 +1,41 @@ +/* + * 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 PhysX +{ + class JointsSubComponentModeSnapRotation final + : public JointsSubComponentModeSnap + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeSnapRotation() = default; + + // JointsSubComponentModeSnap ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + protected: + // JointsSubComponentModeSnap ... + void DisplaySpecificSnapType( + const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay, + const AZ::Vector3& jointPosition, + const AZ::Vector3& snapDirection, + float snapLength) override; + + private: + AZ::Vector3 m_resetRotation; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.cpp new file mode 100644 index 0000000000..becb79a1d9 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.cpp @@ -0,0 +1,90 @@ +/* + * 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 + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeTranslation, AZ::SystemAllocator, 0); + + JointsSubComponentModeTranslation::JointsSubComponentModeTranslation() + : m_manipulator( + AzToolsFramework::TranslationManipulators::Dimensions::Three, AZ::Transform::Identity(), AZ::Vector3::CreateOne()) + { + } + + void JointsSubComponentModeTranslation::Setup(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(idPair.GetEntityId()); + + EditorJointRequestBus::EventResult( + m_resetValue, idPair, &EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Position); + + m_manipulator.SetSpace(worldTransform); + m_manipulator.SetLocalPosition(m_resetValue); + + m_manipulator.AddEntityComponentIdPair(idPair); + m_manipulator.Register(AzToolsFramework::g_mainManipulatorManagerId); + AzToolsFramework::ConfigureTranslationManipulatorAppearance3d(&m_manipulator); + m_manipulator.InstallLinearManipulatorMouseMoveCallback( + [this, idPair](const AzToolsFramework::LinearManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition(), idPair); + }); + + m_manipulator.InstallPlanarManipulatorMouseMoveCallback( + [this, idPair](const AzToolsFramework::PlanarManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition(), idPair); + }); + + m_manipulator.InstallSurfaceManipulatorMouseMoveCallback( + [this, idPair](const AzToolsFramework::SurfaceManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition(), idPair); + }); + } + + void JointsSubComponentModeTranslation::Refresh(const AZ::EntityComponentIdPair& idPair) + { + AZ::Vector3 localTranslation; + EditorJointRequestBus::EventResult( + localTranslation, idPair, &EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Position); + m_manipulator.SetLocalPosition(localTranslation); + } + + void JointsSubComponentModeTranslation::Teardown(const AZ::EntityComponentIdPair& idPair) + { + m_manipulator.RemoveEntityComponentIdPair(idPair); + m_manipulator.Unregister(); + } + + void JointsSubComponentModeTranslation::ResetValues(const AZ::EntityComponentIdPair& idPair) + { + PhysX::EditorJointRequestBus::Event( + idPair, &EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, m_resetValue); + m_manipulator.SetLocalPosition(m_resetValue); + } + + void JointsSubComponentModeTranslation::OnManipulatorMoved(const AZ::Vector3& position, const AZ::EntityComponentIdPair& idPair) + { + m_manipulator.SetLocalPosition(position); + PhysX::EditorJointRequestBus::Event( + idPair, &EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, position); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.h new file mode 100644 index 0000000000..2e25556889 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.h @@ -0,0 +1,43 @@ +/* + * 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 + +namespace AZ +{ + class Vector3; +} // namespace AZ + +namespace PhysX +{ + class JointsSubComponentModeTranslation final + : public PhysXSubComponentModeBase + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeTranslation(); + + // PhysXSubComponentModeBase ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void Refresh(const AZ::EntityComponentIdPair& idPair) override; + void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + private: + void OnManipulatorMoved(const AZ::Vector3& position, const AZ::EntityComponentIdPair& idPair); + + AZ::Vector3 m_resetValue = AZ::Vector3::CreateZero(); + AzToolsFramework::TranslationManipulators m_manipulator; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/PhysXSubComponentModeBase.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/PhysXSubComponentModeBase.h new file mode 100644 index 0000000000..0478d6e1ee --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/PhysXSubComponentModeBase.h @@ -0,0 +1,48 @@ +/* + * 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 AZ +{ + class EntityComponentIdPair; +} // namespace AZ + +namespace AzToolsFramework::ViewportInteraction +{ + struct MouseInteractionEvent; +} // namespace AzToolsFramework::ViewportInteraction + +namespace PhysX +{ + class PhysXSubComponentModeBase + { + public: + virtual ~PhysXSubComponentModeBase() = default; + + //! Called when the mode is entered to initialize the mode. + //! @param idPair The entity/component id pair. + virtual void Setup(const AZ::EntityComponentIdPair& idPair) = 0; + + //! Called when the mode needs to refresh it's values. + //! @param idPair The entity/component id pair. + virtual void Refresh(const AZ::EntityComponentIdPair& idPair) = 0; + + //! Called when the mode exits to perform cleanup. + //! @param idPair The entity/component id pair. + virtual void Teardown(const AZ::EntityComponentIdPair& idPair) = 0; + + //! Called when reset hot key is pressed. + //! Should reset values in the sub component mode to sensible defaults. + //! @param idPair The entity/component id pair. + virtual void ResetValues(const AZ::EntityComponentIdPair& idPair) = 0; + + //! Additional mouse handling by sub-component mode. Does not absorb mouse event. + virtual void HandleMouseInteraction( + [[maybe_unused]] const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) {}; + }; +} // namespace PhysX diff --git a/Gems/PhysX/Code/Include/PhysX/EditorJointBus.h b/Gems/PhysX/Code/Include/PhysX/EditorJointBus.h index e62a8b7e15..20145f1f76 100644 --- a/Gems/PhysX/Code/Include/PhysX/EditorJointBus.h +++ b/Gems/PhysX/Code/Include/PhysX/EditorJointBus.h @@ -9,59 +9,58 @@ #include #include +#include +#include namespace PhysX { - /// Pair of floating point values for angular limits. - using AngleLimitsFloatPair = AZStd::pair; - - /// Messages serviced by Editor Joint Components. + //! Messages serviced by Editor Joint Components. class EditorJointRequests : public AZ::EntityComponentBus { public: static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - /// Get bool parameter value identified by name. - /// @return Value of bool parameter. + //! Get bool parameter value identified by name. + //! @return Value of bool parameter. virtual bool GetBoolValue(const AZStd::string& parameterName) = 0; - /// Get entityID parameter value identified by name. - /// @return Value of entityID parameter. + //! Get entityID parameter value identified by name. + //! @return Value of entityID parameter. virtual AZ::EntityId GetEntityIdValue(const AZStd::string& parameterName) = 0; - /// Get linear parameter value identified by name. - /// @return Value of linear value parameter. + //! Get linear parameter value identified by name. + //! @return Value of linear value parameter. virtual float GetLinearValue(const AZStd::string& parameterName) = 0; - /// Get linear parameter value pair identified by name. - /// @return Linear parameter value pair. + //! Get linear parameter value pair identified by name. + //! @return Linear parameter value pair. virtual AngleLimitsFloatPair GetLinearValuePair(const AZStd::string& parameterName) = 0; - /// Get vector3 value identified by name. - /// @return Vector3 parameter value. + //! Get vector3 value identified by name. + //! @return Vector3 parameter value. virtual AZ::Vector3 GetVector3Value(const AZStd::string& parameterName) = 0; - /// Get transform value identified by name. - /// @return Transform parameter value. + //! Get transform value identified by name. + //! @return Transform parameter value. virtual AZ::Transform GetTransformValue(const AZStd::string& parameterName) = 0; - /// Checks if parameter is used. - virtual bool IsParameterUsed(const AZStd::string& parameterName) = 0; + //! Get the Sub Component modes to enable. + virtual AZStd::vector GetSubComponentModesState() = 0; - /// Set bool parameter value identified by name. + //! Set bool parameter value identified by name. virtual void SetBoolValue(const AZStd::string& parameterName, bool value) = 0; - /// Set entity ID parameter value identified by name. + //! Set entity ID parameter value identified by name. virtual void SetEntityIdValue(const AZStd::string& parameterName, AZ::EntityId value) = 0; - /// Set linear parameter value identified by name. + //! Set linear parameter value identified by name. virtual void SetLinearValue(const AZStd::string& parameterName, float value) = 0; - /// Set linear parameter value pair identified by name. + //! Set linear parameter value pair identified by name. virtual void SetLinearValuePair(const AZStd::string& parameterName, const AngleLimitsFloatPair& valuePair) = 0; - /// Set vector3 parameter value identified by name. + //! Set vector3 parameter value identified by name. virtual void SetVector3Value(const AZStd::string& parameterName, const AZ::Vector3& value) = 0; }; using EditorJointRequestBus = AZ::EBus; diff --git a/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp b/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp index da000baeed..92952bcdaa 100644 --- a/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp @@ -13,7 +13,8 @@ #include #include -#include +#include +#include #include #include @@ -73,9 +74,8 @@ namespace PhysX AzToolsFramework::EditorComponentSelectionNotificationsBus::Handler::BusConnect(entityId); AzToolsFramework::EditorComponentSelectionRequestsBus::Handler* selection = this; - m_componentModeDelegate.ConnectWithSingleComponentMode < - EditorBallJointComponent, EditorBallJointComponentMode>( - AZ::EntityComponentIdPair(entityId, GetId()), selection); + m_componentModeDelegate.ConnectWithSingleComponentMode( + AZ::EntityComponentIdPair(entityId, GetId()), selection); PhysX::EditorJointRequestBus::Handler::BusConnect(AZ::EntityComponentIdPair(entityId, GetId())); } @@ -100,23 +100,19 @@ namespace PhysX float EditorBallJointComponent::GetLinearValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxForce) { return m_config.m_forceMax; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxTorque) { return m_config.m_torqueMax; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - return m_swingLimit.m_standardLimitConfig.m_tolerance; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Damping) { return m_swingLimit.m_standardLimitConfig.m_damping; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Stiffness) { return m_swingLimit.m_standardLimitConfig.m_stiffness; } @@ -126,7 +122,7 @@ namespace PhysX AngleLimitsFloatPair EditorBallJointComponent::GetLinearValuePair(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterSwingLimit) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::SwingLimit) { return AngleLimitsFloatPair(m_swingLimit.m_limitY, m_swingLimit.m_limitZ); } @@ -134,49 +130,58 @@ namespace PhysX return AngleLimitsFloatPair(); } - bool EditorBallJointComponent::IsParameterUsed(const AZStd::string& parameterName) + AZStd::vector EditorBallJointComponent::GetSubComponentModesState() { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce - || parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque - ) + AZStd::vector subModes; + + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition, + JointsComponentModeCommon::ParamaterNames::SnapPosition }); + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation, + JointsComponentModeCommon::ParamaterNames::SnapRotation }); + + if (AZStd::vector baseSubModes = + EditorJointComponent::GetSubComponentModesState(); + !baseSubModes.empty()) { - return m_config.m_breakable; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - return !m_swingLimit.m_standardLimitConfig.m_isSoftLimit; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) - { - return m_swingLimit.m_standardLimitConfig.m_isSoftLimit; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) - { - return m_swingLimit.m_standardLimitConfig.m_isSoftLimit; + subModes.insert(subModes.end(), baseSubModes.begin(), baseSubModes.end()); } - return true; // Sub-component mode always enabled unless disabled explicitly. + if (m_swingLimit.m_standardLimitConfig.m_isLimited) + { + subModes.emplace_back( + JointsComponentModeCommon::SubModeParamaterState{ JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits, + JointsComponentModeCommon::ParamaterNames::SwingLimit }); + + if (m_swingLimit.m_standardLimitConfig.m_isSoftLimit) + { + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::Damping, JointsComponentModeCommon::ParamaterNames::Damping }); + subModes.emplace_back( + JointsComponentModeCommon::SubModeParamaterState{ JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness, + JointsComponentModeCommon::ParamaterNames::Stiffness }); + } + } + + return subModes; } void EditorBallJointComponent::SetLinearValue(const AZStd::string& parameterName, float value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxForce) { m_config.m_forceMax = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxTorque) { m_config.m_torqueMax = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - m_swingLimit.m_standardLimitConfig.m_tolerance = value; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Damping) { m_swingLimit.m_standardLimitConfig.m_damping = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Stiffness) { m_swingLimit.m_standardLimitConfig.m_stiffness = value; } @@ -184,7 +189,7 @@ namespace PhysX void EditorBallJointComponent::SetLinearValuePair(const AZStd::string& parameterName, const AngleLimitsFloatPair& valuePair) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterSwingLimit) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::SwingLimit) { m_swingLimit.m_limitY = valuePair.first; m_swingLimit.m_limitZ = valuePair.second; @@ -193,7 +198,7 @@ namespace PhysX void EditorBallJointComponent::SetBoolValue(const AZStd::string& parameterName, bool value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterComponentMode) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::ComponentMode) { m_swingLimit.m_standardLimitConfig.m_inComponentMode = value; m_config.m_inComponentMode = value; @@ -202,10 +207,6 @@ namespace PhysX &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay , AzToolsFramework::Refresh_EntireTree); } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterSelectOnSnap) - { - m_config.m_selectLeadOnSnap = value; - } } void EditorBallJointComponent::DisplayEntityViewport( @@ -228,7 +229,7 @@ namespace PhysX EditorJointRequestBus::EventResult(localTransform, AZ::EntityComponentIdPair(entityId, GetId()), &EditorJointRequests::GetTransformValue, - PhysX::EditorJointComponentMode::s_parameterTransform); + PhysX::JointsComponentModeCommon::ParamaterNames::Transform); AZ::u32 stateBefore = debugDisplay.GetState(); debugDisplay.CullOff(); diff --git a/Gems/PhysX/Code/Source/EditorBallJointComponent.h b/Gems/PhysX/Code/Source/EditorBallJointComponent.h index 1702532a88..ad925dc79d 100644 --- a/Gems/PhysX/Code/Source/EditorBallJointComponent.h +++ b/Gems/PhysX/Code/Source/EditorBallJointComponent.h @@ -41,7 +41,7 @@ namespace PhysX // PhysX::EditorJointRequests float GetLinearValue(const AZStd::string& parameterName) override; AngleLimitsFloatPair GetLinearValuePair(const AZStd::string& parameterName) override; - bool IsParameterUsed(const AZStd::string& parameterName) override; + AZStd::vector GetSubComponentModesState() override; void SetBoolValue(const AZStd::string& parameterName, bool value) override; void SetLinearValue(const AZStd::string& parameterName, float value) override; void SetLinearValuePair(const AZStd::string& parameterName, const AngleLimitsFloatPair& valuePair) override; diff --git a/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp b/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp index bf5af6b78d..94f57690ba 100644 --- a/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include namespace PhysX @@ -70,9 +70,8 @@ namespace PhysX AzToolsFramework::EditorComponentSelectionNotificationsBus::Handler::BusConnect(entityId); AzToolsFramework::EditorComponentSelectionRequestsBus::Handler* selection = this; - m_componentModeDelegate.ConnectWithSingleComponentMode < - EditorFixedJointComponent, EditorFixedJointComponentMode>( - AZ::EntityComponentIdPair(entityId, GetId()), selection); + m_componentModeDelegate.ConnectWithSingleComponentMode( + AZ::EntityComponentIdPair(entityId, GetId()), selection); PhysX::EditorJointRequestBus::Handler::BusConnect(AZ::EntityComponentIdPair(entityId, GetId())); } @@ -91,4 +90,9 @@ namespace PhysX m_config.m_followerEntity = GetEntityId(); // joint is always in the same entity as the follower body. gameEntity->CreateComponent(m_config.ToGameTimeConfig(), m_config.ToGenericProperties()); } + + AZStd::vector EditorFixedJointComponent::GetSubComponentModesState() + { + return EditorJointComponent::GetSubComponentModesState(); + } } diff --git a/Gems/PhysX/Code/Source/EditorFixedJointComponent.h b/Gems/PhysX/Code/Source/EditorFixedJointComponent.h index 10056020d8..f32243776d 100644 --- a/Gems/PhysX/Code/Source/EditorFixedJointComponent.h +++ b/Gems/PhysX/Code/Source/EditorFixedJointComponent.h @@ -37,6 +37,9 @@ namespace PhysX // EditorComponentBase void BuildGameEntity(AZ::Entity* gameEntity) override; + // EditorJointComponent + AZStd::vector GetSubComponentModesState() override; + private: using ComponentModeDelegate = AzToolsFramework::ComponentModeFramework::ComponentModeDelegate; ComponentModeDelegate m_componentModeDelegate; ///< Responsible for detecting ComponentMode activation diff --git a/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp b/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp index 6676b9865e..5537502327 100644 --- a/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp @@ -12,8 +12,9 @@ #include #include +#include +#include #include -#include #include #include @@ -74,7 +75,7 @@ namespace PhysX AzToolsFramework::EditorComponentSelectionRequestsBus::Handler* selection = this; m_componentModeDelegate.ConnectWithSingleComponentMode < - EditorHingeJointComponent, EditorHingeJointComponentMode>( + EditorHingeJointComponent, JointsComponentMode>( AZ::EntityComponentIdPair(entityId, GetId()), selection); PhysX::EditorJointRequestBus::Handler::BusConnect(AZ::EntityComponentIdPair(entityId, GetId())); @@ -100,23 +101,19 @@ namespace PhysX float EditorHingeJointComponent::GetLinearValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxForce) { return m_config.m_forceMax; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxTorque) { return m_config.m_torqueMax; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - return m_angularLimit.m_standardLimitConfig.m_tolerance; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Damping) { return m_angularLimit.m_standardLimitConfig.m_damping; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Stiffness) { return m_angularLimit.m_standardLimitConfig.m_stiffness; } @@ -126,7 +123,7 @@ namespace PhysX AngleLimitsFloatPair EditorHingeJointComponent::GetLinearValuePair(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterAngularPair) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::TwistLimits) { return AngleLimitsFloatPair(m_angularLimit.m_limitPositive, m_angularLimit.m_limitNegative); } @@ -134,33 +131,41 @@ namespace PhysX return AngleLimitsFloatPair(); } - bool EditorHingeJointComponent::IsParameterUsed(const AZStd::string& parameterName) + AZStd::vector EditorHingeJointComponent::GetSubComponentModesState() { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce - || parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque - ) + AZStd::vector subModes; + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition, + JointsComponentModeCommon::ParamaterNames::SnapPosition }); + + if (AZStd::vector baseSubModes = + EditorJointComponent::GetSubComponentModesState(); + !baseSubModes.empty()) { - return m_config.m_breakable; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - return !m_angularLimit.m_standardLimitConfig.m_isSoftLimit; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) - { - return m_angularLimit.m_standardLimitConfig.m_isSoftLimit; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) - { - return m_angularLimit.m_standardLimitConfig.m_isSoftLimit; + subModes.insert(subModes.end(), baseSubModes.begin(), baseSubModes.end()); } - return true; // Sub-component mode always enabled unless disabled explicitly. + if (m_angularLimit.m_standardLimitConfig.m_isLimited) + { + subModes.emplace_back( + JointsComponentModeCommon::SubModeParamaterState{ JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits, + JointsComponentModeCommon::ParamaterNames::TwistLimits }); + + if (m_angularLimit.m_standardLimitConfig.m_isSoftLimit) + { + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::Damping, JointsComponentModeCommon::ParamaterNames::Damping }); + subModes.emplace_back( + JointsComponentModeCommon::SubModeParamaterState{ JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness, + JointsComponentModeCommon::ParamaterNames::Stiffness }); + } + } + return subModes; } void EditorHingeJointComponent::SetBoolValue(const AZStd::string& parameterName, bool value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterComponentMode) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::ComponentMode) { m_angularLimit.m_standardLimitConfig.m_inComponentMode = value; m_config.m_inComponentMode = value; @@ -169,31 +174,23 @@ namespace PhysX &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay , AzToolsFramework::Refresh_EntireTree); } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterSelectOnSnap) - { - m_config.m_selectLeadOnSnap = value; - } } void EditorHingeJointComponent::SetLinearValue(const AZStd::string& parameterName, float value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxForce) { m_config.m_forceMax = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxTorque) { m_config.m_torqueMax = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - m_angularLimit.m_standardLimitConfig.m_tolerance = value; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Damping) { m_angularLimit.m_standardLimitConfig.m_damping = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Stiffness) { m_angularLimit.m_standardLimitConfig.m_stiffness = value; } @@ -201,7 +198,7 @@ namespace PhysX void EditorHingeJointComponent::SetLinearValuePair(const AZStd::string& parameterName, const AngleLimitsFloatPair& valuePair) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterAngularPair) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::TwistLimits) { m_angularLimit.m_limitPositive = valuePair.first; m_angularLimit.m_limitNegative = valuePair.second; @@ -267,7 +264,7 @@ namespace PhysX EditorJointRequestBus::EventResult(localTransform, AZ::EntityComponentIdPair(entityId, GetId()), &EditorJointRequests::GetTransformValue, - PhysX::EditorJointComponentMode::s_parameterTransform); + PhysX::JointsComponentModeCommon::ParamaterNames::Transform); debugDisplay.PushMatrix(worldTransform); debugDisplay.PushMatrix(localTransform); diff --git a/Gems/PhysX/Code/Source/EditorHingeJointComponent.h b/Gems/PhysX/Code/Source/EditorHingeJointComponent.h index 7c5bd8ad2f..6a2010464e 100644 --- a/Gems/PhysX/Code/Source/EditorHingeJointComponent.h +++ b/Gems/PhysX/Code/Source/EditorHingeJointComponent.h @@ -41,7 +41,7 @@ namespace PhysX // PhysX::EditorJointRequests float GetLinearValue(const AZStd::string& parameterName) override; AngleLimitsFloatPair GetLinearValuePair(const AZStd::string& parameterName) override; - bool IsParameterUsed(const AZStd::string& parameterName) override; + AZStd::vector GetSubComponentModesState() override; void SetBoolValue(const AZStd::string& parameterName, bool value) override; void SetLinearValue(const AZStd::string& parameterName, float value) override; void SetLinearValuePair(const AZStd::string& parameterName, const AngleLimitsFloatPair& valuePair) override; diff --git a/Gems/PhysX/Code/Source/EditorJointComponent.cpp b/Gems/PhysX/Code/Source/EditorJointComponent.cpp index 7b2d612cf1..88e192026d 100644 --- a/Gems/PhysX/Code/Source/EditorJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorJointComponent.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include @@ -134,21 +134,18 @@ namespace PhysX bool EditorJointComponent::GetBoolValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterComponentMode) + if (parameterName == JointsComponentModeCommon::ParamaterNames::ComponentMode) { return m_config.m_inComponentMode; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterSelectOnSnap) - { - return m_config.m_selectLeadOnSnap; - } + AZ_Error("EditorJointComponent::GetBoolValue", false, "bool parameter not recognized: %s", parameterName.c_str()); return false; } AZ::EntityId EditorJointComponent::GetEntityIdValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterLeadEntity) + if (parameterName == JointsComponentModeCommon::ParamaterNames::LeadEntity) { return m_config.m_leadEntity; } @@ -160,11 +157,11 @@ namespace PhysX float EditorJointComponent::GetLinearValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == JointsComponentModeCommon::ParamaterNames::MaxForce) { return m_config.m_forceMax; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == JointsComponentModeCommon::ParamaterNames::MaxTorque) { return m_config.m_torqueMax; } @@ -181,7 +178,7 @@ namespace PhysX AZ::Transform EditorJointComponent::GetTransformValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterTransform) + if (parameterName == JointsComponentModeCommon::ParamaterNames::Transform) { return AZ::Transform::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateFromEulerAnglesDegrees(m_config.m_localRotation), m_config.m_localPosition); @@ -192,11 +189,11 @@ namespace PhysX AZ::Vector3 EditorJointComponent::GetVector3Value(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterPosition) + if (parameterName == JointsComponentModeCommon::ParamaterNames::Position) { return m_config.m_localPosition; } - if (parameterName == PhysX::EditorJointComponentMode::s_parameterRotation) + if (parameterName == JointsComponentModeCommon::ParamaterNames::Rotation) { return m_config.m_localRotation; } @@ -204,24 +201,27 @@ namespace PhysX return AZ::Vector3::CreateZero(); } - bool EditorJointComponent::IsParameterUsed(const AZStd::string& parameterName) + AZStd::vector EditorJointComponent::GetSubComponentModesState() { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce - || parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque - ) + AZStd::vector subModes; + if (m_config.m_breakable) { - return m_config.m_breakable; + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce, JointsComponentModeCommon::ParamaterNames::MaxForce }); + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque, + JointsComponentModeCommon::ParamaterNames::MaxTorque }); } - return true; // Sub-component mode always enabled unless disabled explicitly. + return subModes; } void EditorJointComponent::SetLinearValue(const AZStd::string& parameterName, float value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == JointsComponentModeCommon::ParamaterNames::MaxForce) { m_config.m_forceMax = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == JointsComponentModeCommon::ParamaterNames::MaxTorque) { m_config.m_torqueMax = value; } @@ -235,11 +235,11 @@ namespace PhysX void EditorJointComponent::SetVector3Value(const AZStd::string& parameterName, const AZ::Vector3& value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterPosition) + if (parameterName == JointsComponentModeCommon::ParamaterNames::Position) { m_config.m_localPosition = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterRotation) + else if (parameterName == JointsComponentModeCommon::ParamaterNames::Rotation) { m_config.m_localRotation = value; } @@ -247,7 +247,7 @@ namespace PhysX void EditorJointComponent::SetBoolValue(const AZStd::string& parameterName, bool value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterComponentMode) + if (parameterName == JointsComponentModeCommon::ParamaterNames::ComponentMode) { m_config.m_inComponentMode = value; @@ -255,15 +255,11 @@ namespace PhysX &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay , AzToolsFramework::Refresh_EntireTree); } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterSelectOnSnap) - { - m_config.m_selectLeadOnSnap = value; - } } void EditorJointComponent::SetEntityIdValue(const AZStd::string& parameterName, AZ::EntityId value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterLeadEntity) + if (parameterName == JointsComponentModeCommon::ParamaterNames::LeadEntity) { m_config.SetLeadEntityId(value); } diff --git a/Gems/PhysX/Code/Source/EditorJointComponent.h b/Gems/PhysX/Code/Source/EditorJointComponent.h index 8e92e9820a..69142e6aed 100644 --- a/Gems/PhysX/Code/Source/EditorJointComponent.h +++ b/Gems/PhysX/Code/Source/EditorJointComponent.h @@ -56,7 +56,7 @@ namespace PhysX AngleLimitsFloatPair GetLinearValuePair(const AZStd::string& parameterName) override; AZ::Transform GetTransformValue(const AZStd::string& parameterName) override; AZ::Vector3 GetVector3Value(const AZStd::string& parameterName) override; - bool IsParameterUsed(const AZStd::string& parameterName) override; + AZStd::vector GetSubComponentModesState() override; void SetBoolValue(const AZStd::string& parameterName, bool value) override; void SetEntityIdValue(const AZStd::string& parameterName, AZ::EntityId value) override; void SetLinearValue(const AZStd::string& parameterName, float value) override; diff --git a/Gems/PhysX/Code/physx_editor_files.cmake b/Gems/PhysX/Code/physx_editor_files.cmake index 82f26feff3..5c0c038976 100644 --- a/Gems/PhysX/Code/physx_editor_files.cmake +++ b/Gems/PhysX/Code/physx_editor_files.cmake @@ -82,7 +82,6 @@ set(FILES Editor/ComboBoxEditButtonPair.cpp Editor/ColliderComponentMode.h Editor/ColliderComponentMode.cpp - Editor/ColliderSubComponentMode.h Editor/ColliderOffsetMode.h Editor/ColliderOffsetMode.cpp Editor/ColliderBoxMode.h @@ -99,36 +98,35 @@ set(FILES Editor/DebugDraw.h Editor/PolygonPrismMeshUtils.cpp Editor/PolygonPrismMeshUtils.h - Editor/EditorJointComponentMode.cpp - Editor/EditorJointComponentMode.h + Editor/EditorJointCommon.h Editor/EditorJointConfiguration.cpp Editor/EditorJointConfiguration.h - Editor/EditorJointTypeDrawer.cpp - Editor/EditorJointTypeDrawer.h - Editor/EditorJointTypeDrawerBus.h - Editor/EditorSubComponentModeAngleCone.cpp - Editor/EditorSubComponentModeAngleCone.h - Editor/EditorSubComponentModeAnglePair.cpp - Editor/EditorSubComponentModeAnglePair.h - Editor/EditorSubComponentModeBase.cpp - Editor/EditorSubComponentModeBase.h - Editor/EditorSubComponentModeLinear.cpp - Editor/EditorSubComponentModeLinear.h - Editor/EditorSubComponentModeRotation.cpp - Editor/EditorSubComponentModeRotation.h - Editor/EditorSubComponentModeSnap.cpp - Editor/EditorSubComponentModeSnap.h - Editor/EditorSubComponentModeSnapPosition.cpp - Editor/EditorSubComponentModeSnapPosition.h - Editor/EditorSubComponentModeSnapRotation.cpp - Editor/EditorSubComponentModeSnapRotation.h - Editor/EditorSubComponentModeVec3.cpp - Editor/EditorSubComponentModeVec3.h Editor/EditorViewportEntityPicker.cpp Editor/EditorViewportEntityPicker.h Editor/Source/Components/EditorSystemComponent.h Editor/Source/Components/EditorSystemComponent.cpp + Editor/Source/ComponentModes/Joints/JointsComponentMode.h + Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp + Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.h + Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.cpp + Editor/Source/ComponentModes/PhysXSubComponentModeBase.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.cpp Editor/Source/Configuration/PhysXEditorSettingsRegistryManager.h Editor/Source/Configuration/PhysXEditorSettingsRegistryManager.cpp ) From fa47b35580e1c2e92c6ac3fdfa09a96ef96fb98c Mon Sep 17 00:00:00 2001 From: jonawals Date: Thu, 30 Sep 2021 15:36:42 +0100 Subject: [PATCH 087/115] Call sites for activating/deactivating viewport editor modes. (#4265) * Provisional impl and testing of central state tracker. Signed-off-by: John * Add missing namespace comment. Signed-off-by: John * ViewportEditorModeState -> ViewportEditorModes Signed-off-by: John * ViewportEditorModesTracker -> ViewportEditorModeTracker Signed-off-by: John * GetEditorModeState ->GetViewportEditorModes Signed-off-by: John * GetNumTrackedViewports -> GetTrackedViewportCount Signed-off-by: John * IsViewportStateBeingTracked -> IsViewportModeTracked Signed-off-by: John * Fix API comments. Signed-off-by: John * Delete hangover file. Signed-off-by: John * Delete more hangover files. Signed-off-by: John * Minor member name refactor. Signed-off-by: John * Refactor nonclemanture. Signed-off-by: John * Rename Enter/ExitMode to Register/UnregisterMode. Signed-off-by: John * Error and warning msgs now return AZ::Outcomes. Signed-off-by: John * Change all nomenclature to Activate/Deactivate for consistency. Signed-off-by: John * Change tense of notification bus methods. Signed-off-by: John * Fix malformed string format. Signed-off-by: John * Fix malformed string format (again). Signed-off-by: John * Fix Linux warning. Signed-off-by: John * Call sites for editor mode activate/deactivate. Signed-off-by: John * Move Component editor mode logic to ComponentModeCollection. Signed-off-by: John * Delete non-source data. Signed-off-by: John * Remove line breaks and forward declare class. Signed-off-by: John * Remove constructors without ViewportEditorModeTrackerInterface ptr. Signed-off-by: John * Add integration tests for viewport editor modes. Signed-off-by: John * Address PR comments. Signed-off-by: John --- .../ComponentMode/ComponentModeCollection.cpp | 19 ++- .../ComponentMode/ComponentModeCollection.h | 4 +- .../PropertyEditor/PropertyEntityIdCtrl.cpp | 5 +- .../UnitTest/AzToolsFrameworkTestHelpers.h | 6 +- .../EditorDefaultSelection.cpp | 8 +- .../EditorDefaultSelection.h | 6 +- .../EditorInteractionSystemComponent.cpp | 24 +++- .../EditorInteractionSystemComponent.h | 7 + ...ractionSystemViewportSelectionRequestBus.h | 5 +- .../EditorPickEntitySelection.cpp | 8 +- .../EditorPickEntitySelection.h | 6 +- .../ViewportEditorModeTracker.cpp | 16 --- .../ViewportEditorModeTracker.h | 6 - ...EditorTransformComponentSelectionTests.cpp | 5 +- .../Viewport/ViewportEditorModeTests.cpp | 131 +++++++++++++----- 15 files changed, 182 insertions(+), 74 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index 0259142135..4d849466ee 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -8,8 +8,9 @@ #include "ComponentModeCollection.h" -#include #include +#include +#include namespace AzToolsFramework { @@ -17,7 +18,7 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(ComponentModeCollection, AZ::SystemAllocator, 0) - static const char* const s_nextActiveComponentModeTitle = "Edit Next"; + static const char* const s_nextActiveComponentModeTitle = "Edit Next"; static const char* const s_previousActiveComponentModeTitle = "Edit Previous"; static const char* const s_nextActiveComponentModeDesc = "Move to the next component"; static const char* const s_prevActiveComponentModeDesc = "Move to the previous component"; @@ -119,6 +120,11 @@ namespace AzToolsFramework } }; + ComponentModeCollection::ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + : m_viewportEditorModeTracker(viewportEditorModeTracker) + { + } + void ComponentModeCollection::AddComponentMode( const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid componentType, const ComponentModeFactoryFunction& componentModeBuilder) @@ -209,6 +215,11 @@ namespace AzToolsFramework GetEntityContextId(), &EditorComponentModeNotifications::EnteredComponentMode, m_activeComponentTypes); + // this call to activate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); + // enable actions for the first/primary ComponentMode // note: if multiple ComponentModes are activated at the same time, actions // are not available together, the 'active' mode will bind its actions one at a time @@ -282,6 +293,10 @@ namespace AzToolsFramework &EditorComponentModeNotifications::LeftComponentMode, m_activeComponentTypes); + // this call to deactivate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); // clear stored modes and builders for this ComponentMode // TLDR: avoid 'use after free' error diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h index 7dd97dc0c9..9e299d2323 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h @@ -15,6 +15,7 @@ namespace AzToolsFramework { class EditorMetricsEventsBusTraits; + class ViewportEditorModeTrackerInterface; namespace ComponentModeFramework { @@ -25,7 +26,7 @@ namespace AzToolsFramework AZ_CLASS_ALLOCATOR_DECL /// @cond - ComponentModeCollection() = default; + explicit ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~ComponentModeCollection() = default; ComponentModeCollection(const ComponentModeCollection&) = delete; ComponentModeCollection& operator=(const ComponentModeCollection&) = delete; @@ -101,6 +102,7 @@ namespace AzToolsFramework size_t m_selectedComponentModeIndex = 0; ///< Index into the array of active ComponentModes, current index is 'selected' ComponentMode. bool m_adding = false; ///< Are we currently adding individual ComponentModes to the Editor wide ComponentMode. bool m_componentMode = false; ///< Editor (global) ComponentMode flag - is ComponentMode active or not. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. }; } // namespace ComponentModeFramework } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp index f98638fd69..7a9a5a4d7a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp @@ -119,11 +119,12 @@ namespace AzToolsFramework // replace the default input handler with one specific for dealing with // entity selection in the viewport + EditorInteractionSystemViewportSelectionRequestBus::Event( GetEntityContextId(), &EditorInteractionSystemViewportSelection::SetHandler, - [](const EditorVisibleEntityDataCache* entityDataCache) + [](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); if (!pickModeEntityContextId.IsNull()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h index b3a660d0f2..c4aefecce5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -166,11 +167,12 @@ namespace UnitTest m_editorActions.Connect(); const auto viewportHandlerBuilder = - [this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache) + [this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { // create the default viewport (handles ComponentMode) AZStd::unique_ptr defaultSelection = - AZStd::make_unique(entityDataCache); + AZStd::make_unique(entityDataCache, viewportEditorModeTracker); // override the phantom widget so we can use out custom test widget defaultSelection->SetOverridePhantomWidget(&m_editorActions.m_componentModeWidget); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index 7903668409..30958cfbc1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -9,6 +9,7 @@ #include "EditorDefaultSelection.h" #include +#include #include #include #include @@ -19,21 +20,26 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(EditorDefaultSelection, AZ::SystemAllocator, 0) - EditorDefaultSelection::EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache) + EditorDefaultSelection::EditorDefaultSelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) : m_phantomWidget(nullptr) , m_entityDataCache(entityDataCache) + , m_viewportEditorModeTracker(viewportEditorModeTracker) + , m_componentModeCollection(viewportEditorModeTracker) { ActionOverrideRequestBus::Handler::BusConnect(GetEntityContextId()); ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusConnect(); m_manipulatorManager = AZStd::make_shared(AzToolsFramework::g_mainManipulatorManagerId); m_transformComponentSelection = AZStd::make_unique(entityDataCache); + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); } EditorDefaultSelection::~EditorDefaultSelection() { ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusDisconnect(); ActionOverrideRequestBus::Handler::BusDisconnect(); + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); } void EditorDefaultSelection::SetOverridePhantomWidget(QWidget* phantomOverrideWidget) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h index 5763bf227c..e4c794e99e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h @@ -15,6 +15,8 @@ namespace AzToolsFramework { + class ViewportEditorModeTrackerInterface; + //! The default selection/input handler for the editor (includes handling ComponentMode). class EditorDefaultSelection : public ViewportInteraction::InternalViewportSelectionRequests @@ -25,7 +27,7 @@ namespace AzToolsFramework AZ_CLASS_ALLOCATOR_DECL //! @cond - explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache); + EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); EditorDefaultSelection(const EditorDefaultSelection&) = delete; EditorDefaultSelection& operator=(const EditorDefaultSelection&) = delete; virtual ~EditorDefaultSelection(); @@ -110,5 +112,7 @@ namespace AzToolsFramework AZStd::shared_ptr m_manipulatorManager; //!< The default manipulator manager. ViewportInteraction::MouseInteraction m_currentInteraction; //!< Current mouse interaction to be used for drawing manipulators. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. + }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp index 7002436d13..5d03231aab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp @@ -10,9 +10,24 @@ #include #include +#include namespace AzToolsFramework { + EditorInteractionSystemComponent::EditorInteractionSystemComponent() + : m_viewportEditorMode(AZStd::make_unique()) + { + AZ_Assert(AZ::Interface::Get() == nullptr, "Unexpected registration of viewport editor mode tracker.") + AZ::Interface::Register(m_viewportEditorMode.get()); + } + + EditorInteractionSystemComponent::~EditorInteractionSystemComponent() + { + m_interactionRequests.reset(); + AZ_Assert(AZ::Interface::Get() != nullptr, "Unexpected unregistration of viewport editor mode tracker.") + AZ::Interface::Unregister(m_viewportEditorMode.get()); + } + void EditorInteractionSystemComponent::Activate() { EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId()); @@ -41,7 +56,8 @@ namespace AzToolsFramework return m_interactionRequests->InternalHandleMouseManipulatorInteraction(mouseInteraction); } - void EditorInteractionSystemComponent::SetHandler(const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) + void EditorInteractionSystemComponent::SetHandler( + const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) { // when setting a handler, make sure we're connected to the ViewportDebugDisplayEventBus so we // can forward calls to the specific type implementing ViewportSelectionRequests @@ -59,7 +75,7 @@ namespace AzToolsFramework m_entityDataCache = AZStd::make_unique(); m_interactionRequests.reset(); // BusConnect/Disconnect in constructor/destructor, // so have to reset before assigning the new one - m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get()); + m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get(), m_viewportEditorMode.get()); } EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId()); @@ -68,9 +84,9 @@ namespace AzToolsFramework void EditorInteractionSystemComponent::SetDefaultHandler() { SetHandler( - [](const EditorVisibleEntityDataCache* entityDataCache) + [](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h index 17521eab14..856fd2e326 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h @@ -14,6 +14,8 @@ namespace AzToolsFramework { + class ViewportEditorModeTracker; + //! System Component to wrap active input handler. //! EditorInteractionSystemComponent is notified of viewport mouse events from RenderViewport //! and forwards them to a concrete implementation of ViewportSelectionRequests. @@ -26,6 +28,9 @@ namespace AzToolsFramework public: AZ_COMPONENT(EditorInteractionSystemComponent, "{146D0317-AF42-45AB-A953-F54198525DD5}") + EditorInteractionSystemComponent(); + ~EditorInteractionSystemComponent(); + static void Reflect(AZ::ReflectContext* context); // EditorInteractionSystemViewportSelectionRequestBus @@ -54,5 +59,7 @@ namespace AzToolsFramework AZStd::unique_ptr m_interactionRequests; //!< Hold a concrete implementation of //!< ViewportSelectionRequests to handle viewport //!< input and drawing for the Editor. + + AZStd::unique_ptr m_viewportEditorMode; //!< Editor mode tracker for each viewport. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h index ee3f83f74d..3579460ca0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h @@ -17,6 +17,7 @@ namespace AzToolsFramework { class EditorVisibleEntityDataCache; + class ViewportEditorModeTrackerInterface; //! Bus to handle all mouse events originating from the viewport. //! Coordinated by the EditorInteractionSystemComponent @@ -32,8 +33,8 @@ namespace AzToolsFramework }; //! Alias for factory function to create a new type implementing the ViewportSelectionRequests interface. - using ViewportSelectionRequestsBuilderFn = - AZStd::function(const EditorVisibleEntityDataCache*)>; + using ViewportSelectionRequestsBuilderFn = AZStd::function( + const EditorVisibleEntityDataCache*, ViewportEditorModeTrackerInterface*)>; //! Interface for system component implementing the ViewportSelectionRequests interface. //! This interface also includes a setter to set a custom handler also implementing diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp index ea1bc73056..18eda140a0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp @@ -8,6 +8,7 @@ #include "EditorPickEntitySelection.h" +#include #include #include @@ -15,9 +16,12 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(EditorPickEntitySelection, AZ::SystemAllocator, 0) - EditorPickEntitySelection::EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache) + EditorPickEntitySelection::EditorPickEntitySelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) : m_editorHelpers(AZStd::make_unique(entityDataCache)) + , m_viewportEditorModeTracker(viewportEditorModeTracker) { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); } EditorPickEntitySelection::~EditorPickEntitySelection() @@ -26,6 +30,8 @@ namespace AzToolsFramework { ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, m_hoveredEntityId, false); } + + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); } // note: entityIdUnderCursor is the authoritative entityId we get each frame by querying diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h index e8d83af932..62fa4161b7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h @@ -13,6 +13,8 @@ namespace AzToolsFramework { + class ViewportEditorModeTrackerInterface; + //! Viewport interaction that will handle assigning an entity in the viewport to //! an entity field in the entity inspector. class EditorPickEntitySelection : public ViewportInteraction::InternalViewportSelectionRequests @@ -20,7 +22,8 @@ namespace AzToolsFramework public: AZ_CLASS_ALLOCATOR_DECL - EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache); + EditorPickEntitySelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~EditorPickEntitySelection(); private: @@ -32,5 +35,6 @@ namespace AzToolsFramework AZStd::unique_ptr m_editorHelpers; //!< Editor visualization of entities (icons, shapes, debug visuals etc). AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any). AZ::EntityId m_cachedEntityIdUnderCursor; //!< Store the EntityId on each mouse move for use in Display. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 4adddb02e1..105712c789 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -45,22 +45,6 @@ namespace AzToolsFramework return m_editorModes[static_cast(mode)]; } - void ViewportEditorModeTracker::RegisterInterface() - { - if (AZ::Interface::Get() == nullptr) - { - AZ::Interface::Register(this); - } - } - - void ViewportEditorModeTracker::UnregisterInterface() - { - if (AZ::Interface::Get() != nullptr) - { - AZ::Interface::Unregister(this); - } - } - AZ::Outcome ViewportEditorModeTracker::ActivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 6ae68b39b2..5b382c44e7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -41,12 +41,6 @@ namespace AzToolsFramework : public ViewportEditorModeTrackerInterface { public: - //! Registers this object with the AZ::Interface. - void RegisterInterface(); - - //! Unregisters this object with the AZ::Interface. - void UnregisterInterface(); - // ViewportEditorModeTrackerInterface overrides ... AZ::Outcome ActivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; AZ::Outcome DeactivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index 52470f41e3..4229ebb8c4 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -344,9 +344,10 @@ namespace UnitTest using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus; EditorInteractionSystemViewportSelectionRequestBus::Event( AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, - [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache) + [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); // When diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 3954ef6dc6..866d88b7ba 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -7,7 +7,9 @@ */ #include +#include #include +#include #include namespace UnitTest @@ -18,6 +20,7 @@ namespace UnitTest using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo; using ViewportId = ViewportEditorModeInfo::IdType; using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; + using ViewportEditorModeTrackerInterface = AzToolsFramework::ViewportEditorModeTrackerInterface; void ActivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) { @@ -47,6 +50,26 @@ namespace UnitTest } } + void ExpectOnlyModeActive(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) + { + for (auto modeIndex = 0; modeIndex < ViewportEditorModes::NumEditorModes; modeIndex++) + { + const auto currentMode = static_cast(modeIndex); + const bool expectedActive = (mode == currentMode); + EXPECT_EQ(editorModeState.IsModeActive(currentMode), expectedActive); + } + } + + void ExpectOnlyModeInactive(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) + { + for (auto modeIndex = 0; modeIndex < ViewportEditorModes::NumEditorModes; modeIndex++) + { + const auto currentMode = static_cast(modeIndex); + const bool expectedActive = (mode != currentMode); + EXPECT_EQ(editorModeState.IsModeActive(currentMode), expectedActive); + } + } + // Fixture for testing editor mode states class ViewportEditorModesTestsFixture : public ::testing::Test @@ -116,7 +139,7 @@ namespace UnitTest m_editorModes[mode].m_onEnter = true; } - virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onExit = true; } @@ -152,6 +175,22 @@ namespace UnitTest AZStd::array, ViewportEditorModes::NumEditorModes> m_editorModeHandlers; }; + // Fixture for testing the integration of viewport editor mode state tracker + class ViewportEditorModeTrackerIntegrationTestFixture + : public ToolsApplicationFixture + { + public: + void SetUpEditorFixtureImpl() override + { + m_viewportEditorModeTracker = AZ::Interface::Get(); + ASSERT_NE(m_viewportEditorModeTracker, nullptr); + m_viewportEditorModes = m_viewportEditorModeTracker->GetViewportEditorModes({}); + } + + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; + const ViewportEditorModesInterface* m_viewportEditorModes = nullptr; + }; + TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4) { EXPECT_EQ(ViewportEditorModes::NumEditorModes, 4); @@ -168,38 +207,14 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); - - for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) - { - const auto editorMode = static_cast(mode); - if (editorMode == m_selectedEditorMode) - { - EXPECT_TRUE(m_editorModes.IsModeActive(static_cast(editorMode))); - } - else - { - EXPECT_FALSE(m_editorModes.IsModeActive(static_cast(editorMode))); - } - } + ExpectOnlyModeActive(m_editorModes, m_selectedEditorMode); } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { SetAllModesActive(m_editorModes); DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); - - for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) - { - const auto editorMode = static_cast(mode); - if (editorMode == m_selectedEditorMode) - { - EXPECT_FALSE(m_editorModes.IsModeActive(editorMode)); - } - else - { - EXPECT_TRUE(m_editorModes.IsModeActive(editorMode)); - } - } + ExpectOnlyModeInactive(m_editorModes, m_selectedEditorMode); } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively) @@ -298,7 +313,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetTrackedViewportCount(), 0); } - TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) + TEST_F(ViewportEditorModeTrackerTestFixture, ActivatingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -318,7 +333,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError) + TEST_F(ViewportEditorModeTrackerTestFixture, DeactivatingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -351,7 +366,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); } - TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateReturnsError) + TEST_F(ViewportEditorModeTrackerTestFixture, ActivatingViewportEditorModesForExistingIdInThatStateReturnsError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -390,7 +405,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateReturnssError) + TEST_F(ViewportEditorModeTrackerTestFixture, DeactivatingViewportEditorModesForExistingIdNotInThatStateReturnssError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -432,7 +447,7 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - RegisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeRegisterEventForAllSubscribers) + ActivatingViewportEditorModesForExistingIdPublishesOnViewportEditorModeActivateEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -465,7 +480,7 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - UnregisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeUnregisterEventForAllSubscribers) + DeactivatingViewportEditorModesForExistingIdPublishesOnViewportEditorModeDeactivatingEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -495,4 +510,54 @@ namespace UnitTest EXPECT_TRUE(expectedEditorModeSet->second.m_onExit); } } + + TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, InitialViewportEditorModeIsDefault) + { + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default); + } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, EnteringComponentModeAfterInitialStateHasViewportEditorModesDefaultAndComponentModeActive) + { + // When component mode is entered + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, + AZStd::vector{}); + + bool inComponentMode = false; + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( + inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); + + // Expect to be in component mode + EXPECT_TRUE(inComponentMode); + + // Expect the default and component viewport editor modes to be active + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component)); + + // Do not expect the pick and focus viewport editor modes to be active + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick)); + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus)); + } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, + EnteringEditorPickEntitySelectionAfterInitialStateHasOnlyViewportEditorModePickModeActive) + { + // When entering pick mode + using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus; + EditorInteractionSystemViewportSelectionRequestBus::Event( + AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, + [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + { + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); + }); + + // Expect only the pick viewport editor mode to be active + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Pick); + } + + // FocusMode integration tests will follow (LYN-6995) + } // namespace UnitTest From 4d368fe3292e1842713dd991662c9e3e0facb3d1 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Thu, 30 Sep 2021 08:18:12 -0700 Subject: [PATCH 088/115] Fix to capitalization in include via the UI Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- Code/Editor/ViewportTitleDlg.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Editor/ViewportTitleDlg.ui b/Code/Editor/ViewportTitleDlg.ui index 9b02876054..7ba6361cf9 100644 --- a/Code/Editor/ViewportTitleDlg.ui +++ b/Code/Editor/ViewportTitleDlg.ui @@ -142,7 +142,7 @@ AzQtComponents::BreadCrumbs QWidget -
AzQtComponents/Components/Widgets/Breadcrumbs.h
+
AzQtComponents/Components/Widgets/BreadCrumbs.h
1
From ffbc3f1c800b97b390199911878c1b2045e79b04 Mon Sep 17 00:00:00 2001 From: srikappa-amzn <82230713+srikappa-amzn@users.noreply.github.com> Date: Thu, 30 Sep 2021 20:56:11 +0530 Subject: [PATCH 089/115] Fix a bug in recursion of prefab links when checking for dirty prefabs (#4392) * Fix a bug in recursion of prefab links when checking for dirty prefabs Signed-off-by: srikappa-amzn * Added a missing EntityId header Signed-off-by: srikappa-amzn --- .../AzToolsFramework/Prefab/PrefabSystemComponent.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 0d2696f14b..6ef2d756fb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -818,7 +818,14 @@ namespace AzToolsFramework auto linkIterator = m_linkIdMap.find(linkId); if (linkIterator != m_linkIdMap.end()) { - return AreDirtyTemplatesPresent(linkIterator->second.GetSourceTemplateId()); + if (AreDirtyTemplatesPresent(linkIterator->second.GetSourceTemplateId())) + { + return true; + } + else + { + continue; + } } } return false; From b1c82fc0458f51760f391199191df82a38580c4e Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 30 Sep 2021 10:57:54 -0500 Subject: [PATCH 090/115] Updated references to Engine.pak to be lowercase engine.pak (#4397) * Updated references to Engine.pak to be lowercase engine.pak This makes the engine.pak file consistent with naming scheme of other pak files such as assets.pak. It will also help avoid issues with mounting the file on Linux. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Engine.pak now loads correctly in release builds. The check for the file existing was failing in release builds because it was only checking inside packs. OpenPack first checks if the file exists, anyways, so it was safe to remove. Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Co-authored-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> --- .../Application/GameApplication.cpp | 15 ++++++--------- Code/Legacy/CrySystem/SystemInit.cpp | 4 ++-- cmake/Projects.cmake | 6 +++--- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index f759857505..475a7d5504 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -32,17 +32,14 @@ namespace AzGameFramework // at the Assets alias, otherwise to attempting to mount the engine pak // from the Cache folder AZ::IO::FixedMaxPath enginePakPath = AZ::Utils::GetExecutableDirectory(); - enginePakPath /= "Engine.pak"; - if (m_archiveFileIO->Exists(enginePakPath.c_str())) + enginePakPath /= "engine.pak"; + if (!m_archive->OpenPack("@assets@", enginePakPath.Native())) { - m_archive->OpenPack("@assets@", enginePakPath.Native()); - } - else if (enginePakPath.clear(); m_settingsRegistry->Get(enginePakPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) - { - // fall back to checking if there is an Engine.pak in the Asset Cache - enginePakPath /= "Engine.pak"; - if (m_archiveFileIO->Exists(enginePakPath.c_str())) + enginePakPath.clear(); + if (m_settingsRegistry->Get(enginePakPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) { + // fall back to checking Project Cache Root. + enginePakPath /= "engine.pak"; m_archive->OpenPack("@assets@", enginePakPath.Native()); } } diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index 2c70717e8f..3187095094 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -808,7 +808,7 @@ void CSystem::OpenBasicPaks() const char* const assetsDir = "@assets@"; // After game paks to have same search order as with files on disk - m_env.pCryPak->OpenPack(assetsDir, "Engine.pak"); + m_env.pCryPak->OpenPack(assetsDir, "engine.pak"); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_15 @@ -1261,7 +1261,7 @@ AZ_POP_DISABLE_WARNING InlineInitializationProcessing("CSystem::Init Create console"); // Need to load the engine.pak that includes the config files needed during initialization - m_env.pCryPak->OpenPack("@assets@", "Engine.pak"); + m_env.pCryPak->OpenPack("@assets@", "engine.pak"); InitFileSystem_LoadEngineFolders(startupParams); diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index d3f4b33b03..61cb101909 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -151,18 +151,18 @@ if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") if(NOT DEFINED LY_ASSET_DEPLOY_ASSET_TYPE) set(LY_ASSET_DEPLOY_ASSET_TYPE @LY_ASSET_DEPLOY_ASSET_TYPE@) endif() - message(STATUS "Generating ${install_output_folder}/Engine.pak from @full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") + message(STATUS "Generating ${install_output_folder}/engine.pak from @full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") file(MAKE_DIRECTORY "${install_output_folder}") cmake_path(SET cache_product_path "@full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") file(GLOB product_assets "${cache_product_path}/*") if(product_assets) execute_process( - COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_output_folder}/Engine.pak" --format=zip -- ${product_assets} + COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_output_folder}/engine.pak" --format=zip -- ${product_assets} WORKING_DIRECTORY "${cache_product_path}" RESULT_VARIABLE archive_creation_result ) if(archive_creation_result EQUAL 0) - message(STATUS "${install_output_folder}/Engine.pak generated") + message(STATUS "${install_output_folder}/engine.pak generated") endif() endif() endif() From cfbe76fdf639814abb92ad8d1ea30c5b21042165 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 30 Sep 2021 17:29:32 +0100 Subject: [PATCH 091/115] Add call site for activating/deactivating Focus. Signed-off-by: John --- .../FocusMode/FocusModeSystemComponent.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp index e1c04fcb93..3fafb4db81 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp @@ -10,6 +10,7 @@ #include #include +#include namespace AzToolsFramework { @@ -66,7 +67,18 @@ namespace AzToolsFramework { m_focusRoot = entityId; - // TODO - If m_focusRoot != AZ::EntityId(), activate focus mode via ViewportEditorModeTrackerInterface; else, deactivate focus mode + if (auto tracker = AZ::Interface::Get(); + tracker != nullptr) + { + if (!m_focusRoot.IsValid() && entityId.IsValid()) + { + tracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Focus); + } + else if (m_focusRoot.IsValid() && !entityId.IsValid()) + { + tracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Focus); + } + } } void FocusModeSystemComponent::ClearFocusRoot() From 8d67f184c886a6c01b303329201b52b2e588bd6f Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Thu, 30 Sep 2021 10:05:50 -0700 Subject: [PATCH 092/115] LYN-7008 | Focus Mode - Selection unit tests (#4357) * Refactor existing tests and fixtures, split them up in more granular tests, and add more comments. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Refactor test fixture for FocusMode to make it more reusable Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fixture rename, draft of selection test Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Split SetFocus and ClearFocus tests for Editor Focus Mode Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Move BoundsTestComponent to its own file so that it can be reused in Focus Mode Selection tests Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Making progress on selection test. Test compiles now, but selection doesn't seem to be working. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Removed commented out code from previous iteration. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Move BoundsTestComponent under the UnitTest namespace Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Viewport selection tests + minor fixes. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor fixes Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Tests/BoundsTestComponent.cpp | 60 ++++++ .../Tests/BoundsTestComponent.h | 46 +++++ ...EditorTransformComponentSelectionTests.cpp | 79 +------- .../FocusMode/EditorFocusModeFixture.cpp | 78 ++++++++ .../Tests/FocusMode/EditorFocusModeFixture.h | 48 +++++ .../EditorFocusModeSelectionTests.cpp | 135 +++++++++++++ .../Tests/FocusMode/EditorFocusModeTests.cpp | 180 ++++++++---------- .../Prefab/PrefabFocus/PrefabFocusTests.cpp | 156 +++++++++------ .../Tests/aztoolsframeworktests_files.cmake | 5 + 9 files changed, 548 insertions(+), 239 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp create mode 100644 Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h create mode 100644 Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp create mode 100644 Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h create mode 100644 Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp diff --git a/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp new file mode 100644 index 0000000000..11a077f53c --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp @@ -0,0 +1,60 @@ +/* + * 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 +{ + AZ::Aabb BoundsTestComponent::GetEditorSelectionBoundsViewport([[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo) + { + return GetWorldBounds(); + } + + bool BoundsTestComponent::EditorSelectionIntersectRayViewport( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) + { + return AzToolsFramework::AabbIntersectRay(src, dir, GetWorldBounds(), distance); + } + + bool BoundsTestComponent::SupportsEditorRayIntersect() + { + return true; + } + + void BoundsTestComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context) + { + // noop + } + + void BoundsTestComponent::Activate() + { + AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId()); + AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusConnect(GetEntityId()); + } + + void BoundsTestComponent::Deactivate() + { + AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusDisconnect(); + AzFramework::BoundsRequestBus::Handler::BusDisconnect(); + } + + AZ::Aabb BoundsTestComponent::GetWorldBounds() + { + AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(worldFromLocal, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM); + return GetLocalBounds().GetTransformedAabb(worldFromLocal); + } + + AZ::Aabb BoundsTestComponent::GetLocalBounds() + { + return AZ::Aabb::CreateFromMinMax(AZ::Vector3(-0.5f), AZ::Vector3(0.5f)); + } + +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h new file mode 100644 index 0000000000..1aabcfcd64 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h @@ -0,0 +1,46 @@ +/* + * 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 UnitTest +{ + //! Basic component that implements BoundsRequestBus and EditorComponentSelectionRequestsBus to be compatible + //! with the Editor visibility system. + //! Note: Used for simulating selection (picking) in the viewport. + class BoundsTestComponent + : public AzToolsFramework::Components::EditorComponentBase + , public AzFramework::BoundsRequestBus::Handler + , public AzToolsFramework::EditorComponentSelectionRequestsBus::Handler + { + public: + AZ_EDITOR_COMPONENT( + BoundsTestComponent, "{E6312E9D-8489-4677-9980-C93C328BC92C}", AzToolsFramework::Components::EditorComponentBase); + + static void Reflect(AZ::ReflectContext* context); + + // AZ::Component overrides ... + void Activate() override; + void Deactivate() override; + + // EditorComponentSelectionRequestsBus overrides ... + AZ::Aabb GetEditorSelectionBoundsViewport(const AzFramework::ViewportInfo& viewportInfo) override; + bool EditorSelectionIntersectRayViewport( + const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) override; + bool SupportsEditorRayIntersect() override; + + // BoundsRequestBus overrides ... + AZ::Aabb GetWorldBounds() override; + AZ::Aabb GetLocalBounds() override; + }; + +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index 4229ebb8c4..81909ac511 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -22,12 +21,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -41,6 +38,8 @@ #include #include +#include + namespace AZ { std::ostream& operator<<(std::ostream& os, const EntityId entityId) @@ -123,80 +122,6 @@ namespace UnitTest EXPECT_FALSE(m_cache.IsVisibleEntityVisible(m_cache.GetVisibleEntityIndexFromId(m_entityIds[2]).value())); } - //! Basic component that implements BoundsRequestBus and EditorComponentSelectionRequestsBus to be compatible - //! with the Editor visibility system. - //! Note: Used for simulating selection (picking) in the viewport. - class BoundsTestComponent - : public AzToolsFramework::Components::EditorComponentBase - , public AzFramework::BoundsRequestBus::Handler - , public AzToolsFramework::EditorComponentSelectionRequestsBus::Handler - { - public: - AZ_EDITOR_COMPONENT( - BoundsTestComponent, "{E6312E9D-8489-4677-9980-C93C328BC92C}", AzToolsFramework::Components::EditorComponentBase); - - static void Reflect(AZ::ReflectContext* context); - - // AZ::Component overrides ... - void Activate() override; - void Deactivate() override; - - // EditorComponentSelectionRequestsBus overrides ... - AZ::Aabb GetEditorSelectionBoundsViewport(const AzFramework::ViewportInfo& viewportInfo) override; - bool EditorSelectionIntersectRayViewport( - const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) override; - bool SupportsEditorRayIntersect() override; - - // BoundsRequestBus overrides ... - AZ::Aabb GetWorldBounds() override; - AZ::Aabb GetLocalBounds() override; - }; - - AZ::Aabb BoundsTestComponent::GetEditorSelectionBoundsViewport([[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo) - { - return GetWorldBounds(); - } - - bool BoundsTestComponent::EditorSelectionIntersectRayViewport( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) - { - return AzToolsFramework::AabbIntersectRay(src, dir, GetWorldBounds(), distance); - } - - bool BoundsTestComponent::SupportsEditorRayIntersect() - { - return true; - } - - void BoundsTestComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context) - { - // noop - } - - void BoundsTestComponent::Activate() - { - AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId()); - AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusConnect(GetEntityId()); - } - - void BoundsTestComponent::Deactivate() - { - AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusDisconnect(); - AzFramework::BoundsRequestBus::Handler::BusDisconnect(); - } - - AZ::Aabb BoundsTestComponent::GetWorldBounds() - { - AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult(worldFromLocal, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM); - return GetLocalBounds().GetTransformedAabb(worldFromLocal); - } - - AZ::Aabb BoundsTestComponent::GetLocalBounds() - { - return AZ::Aabb::CreateFromMinMax(AZ::Vector3(-0.5f), AZ::Vector3(0.5f)); - } - // Fixture to support testing EditorTransformComponentSelection functionality on an Entity selection. class EditorTransformComponentSelectionFixture : public ToolsApplicationFixture { diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp new file mode 100644 index 0000000000..bc026a4baf --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp @@ -0,0 +1,78 @@ +/* + * 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 AzToolsFramework +{ + void EditorFocusModeFixture::SetUpEditorFixtureImpl() + { + // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // in the unit tests. + AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); + + m_focusModeInterface = AZ::Interface::Get(); + ASSERT_TRUE(m_focusModeInterface != nullptr); + + // register a simple component implementing BoundsRequestBus and EditorComponentSelectionRequestsBus + GetApplication()->RegisterComponentDescriptor(UnitTest::BoundsTestComponent::CreateDescriptor()); + + GenerateTestHierarchy(); + } + + void EditorFocusModeFixture::GenerateTestHierarchy() + { + /* + * City + * |_ Street + * |_ Car + * | |_ Passenger + * |_ SportsCar + * |_ Passenger + */ + + m_entityMap[CityEntityName] = CreateEditorEntity(CityEntityName, AZ::EntityId()); + m_entityMap[StreetEntityName] = CreateEditorEntity(StreetEntityName, m_entityMap[CityEntityName]); + m_entityMap[CarEntityName] = CreateEditorEntity(CarEntityName, m_entityMap[StreetEntityName]); + m_entityMap[Passenger1EntityName] = CreateEditorEntity(Passenger1EntityName, m_entityMap[CarEntityName]); + m_entityMap[SportsCarEntityName] = CreateEditorEntity(SportsCarEntityName, m_entityMap[StreetEntityName]); + m_entityMap[Passenger2EntityName] = CreateEditorEntity(Passenger2EntityName, m_entityMap[SportsCarEntityName]); + + // Add a BoundsTestComponent to the Car entity. + AZ::Entity* entity = GetEntityById(m_entityMap[CarEntityName]); + + entity->Deactivate(); + entity->CreateComponent(); + entity->Activate(); + + // Move the CarEntity so it's out of the way. + AZ::TransformBus::Event(m_entityMap[CarEntityName], &AZ::TransformBus::Events::SetWorldTranslation, CarEntityPosition); + + // Setup the camera so the Car entity is in view. + AzFramework::SetCameraTransform( + m_cameraState, + AZ::Transform::CreateFromQuaternionAndTranslation( + AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 0.0f)), CameraPosition)); + } + + AZ::EntityId EditorFocusModeFixture::CreateEditorEntity(const char* name, AZ::EntityId parentId) + { + AZ::Entity* entity = nullptr; + UnitTest::CreateDefaultEditorEntity(name, &entity); + + // Parent + AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId); + + return entity->GetId(); + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h new file mode 100644 index 0000000000..a461b45e1b --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h @@ -0,0 +1,48 @@ +/* + * 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 + +namespace AzToolsFramework +{ + class EditorFocusModeFixture + : public UnitTest::ToolsApplicationFixture + { + protected: + void SetUpEditorFixtureImpl() override; + + void GenerateTestHierarchy(); + AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId); + + AZStd::unordered_map m_entityMap; + FocusModeInterface* m_focusModeInterface = nullptr; + + public: + AzFramework::CameraState m_cameraState; + + inline static const AZ::Vector3 CameraPosition = AZ::Vector3(10.0f, 15.0f, 10.0f); + + inline static const char* CityEntityName = "City"; + inline static const char* StreetEntityName = "Street"; + inline static const char* CarEntityName = "Car"; + inline static const char* SportsCarEntityName = "SportsCar"; + inline static const char* Passenger1EntityName = "Passenger1"; + inline static const char* Passenger2EntityName = "Passenger2"; + + inline static AZ::Vector3 CarEntityPosition = AZ::Vector3(5.0f, 15.0f, 0.0f); + }; +} diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp new file mode 100644 index 0000000000..750137814d --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp @@ -0,0 +1,135 @@ +/* + * 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 + + +namespace AzToolsFramework +{ + class EditorFocusModeSelectionFixture + : public UnitTest::IndirectCallManipulatorViewportInteractionFixtureMixin + { + public: + void ClickAtWorldPositionOnViewport(const AZ::Vector3& worldPosition) + { + // Calculate the world position in screen space + const auto carScreenPosition = AzFramework::WorldToScreen(worldPosition, m_cameraState); + + // Click the entity in the viewport + m_actionDispatcher->CameraState(m_cameraState)->MousePosition(carScreenPosition)->MouseLButtonDown()->MouseLButtonUp(); + } + }; + + void ClearSelectedEntities() + { + AzToolsFramework::ToolsApplicationRequestBus::Broadcast( + &AzToolsFramework::ToolsApplicationRequestBus::Events::SetSelectedEntities, AzToolsFramework::EntityIdList()); + } + + AzToolsFramework::EntityIdList GetSelectedEntities() + { + AzToolsFramework::EntityIdList selectedEntities; + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( + selectedEntities, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetSelectedEntities); + return selectedEntities; + } + + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnLevel) + { + // Clear the focus, disabling focus mode + m_focusModeInterface->ClearFocusRoot(); + // Clear selection + ClearSelectedEntities(); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(CarEntityPosition); + + // Verify entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); + } + + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnAncestor) + { + // Set the focus on the Street Entity (parent of the test entity) + m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); + // Clear selection + ClearSelectedEntities(); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(CarEntityPosition); + + // Verify entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); + } + + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnItself) + { + // Set the focus on the Car Entity (test entity) + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); + // Clear selection + ClearSelectedEntities(); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(CarEntityPosition); + + // Verify entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); + } + + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnSibling) + { + // Set the focus on the SportsCar Entity (sibling of the test entity) + m_focusModeInterface->SetFocusRoot(m_entityMap[SportsCarEntityName]); + // Clear selection + ClearSelectedEntities(); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(CarEntityPosition); + + // entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 0); + } + + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnDescendant) + { + // Set the focus on the Passenger1 Entity (child of the entity) + m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger1EntityName]); + // Clear selection + ClearSelectedEntities(); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(CarEntityPosition); + + // entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 0); + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp index 5972da58a7..7dfdff655a 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp @@ -6,123 +6,99 @@ * */ -#include -#include -#include -#include -#include +#include namespace AzToolsFramework { - class EditorFocusModeTests - : public ::testing::Test + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_SetFocus) { - protected: - void SetUp() override - { - m_app.Start(m_descriptor); + // When an entity is set as the focus root, GetFocusRoot should return its EntityId. + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); + EXPECT_EQ(m_focusModeInterface->GetFocusRoot(), m_entityMap[CarEntityName]); - // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash - // in the unit tests. - AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); - - GenerateTestHierarchy(); - } - - void GenerateTestHierarchy() - { - /* - * City - * |_ Street - * |_ Car - * | |_ Passenger - * |_ SportsCar - * |_ Passenger - */ - - m_entityMap["cityId"] = CreateEditorEntity("City", AZ::EntityId()); - m_entityMap["streetId"] = CreateEditorEntity("Street", m_entityMap["cityId"]); - m_entityMap["carId"] = CreateEditorEntity("Car", m_entityMap["streetId"]); - m_entityMap["passengerId1"] = CreateEditorEntity("Passenger", m_entityMap["carId"]); - m_entityMap["sportsCarId"] = CreateEditorEntity("SportsCar", m_entityMap["streetId"]); - m_entityMap["passengerId2"] = CreateEditorEntity("Passenger", m_entityMap["sportsCarId"]); - } - - AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId) - { - AZ::Entity* entity = nullptr; - UnitTest::CreateDefaultEditorEntity(name, &entity); - - // Parent - AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId); - - return entity->GetId(); - } - - void TearDown() override - { - m_app.Stop(); - } - - UnitTest::ToolsTestApplication m_app{ "EditorFocusModeTests" }; - AZ::ComponentApplication::Descriptor m_descriptor; - AZStd::unordered_map m_entityMap; - }; - - TEST_F(EditorFocusModeTests, EditorFocusModeTests_SetFocus) - { - FocusModeInterface* focusModeInterface = AZ::Interface::Get(); - EXPECT_TRUE(focusModeInterface != nullptr); - - focusModeInterface->SetFocusRoot(m_entityMap["carId"]); - EXPECT_EQ(focusModeInterface->GetFocusRoot(), m_entityMap["carId"]); - - focusModeInterface->ClearFocusRoot(); - EXPECT_EQ(focusModeInterface->GetFocusRoot(), AZ::EntityId()); + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); } - TEST_F(EditorFocusModeTests, EditorFocusModeTests_IsInFocusSubTree) + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_ClearFocus) { - FocusModeInterface* focusModeInterface = AZ::Interface::Get(); - EXPECT_TRUE(focusModeInterface != nullptr); + // Change the value from the default. + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); - focusModeInterface->ClearFocusRoot(); - - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true); + // Calling ClearFocusRoot restores the default focus root (which is an invalid EntityId). + m_focusModeInterface->ClearFocusRoot(); + EXPECT_EQ(m_focusModeInterface->GetFocusRoot(), AZ::EntityId()); + } - focusModeInterface->SetFocusRoot(m_entityMap["streetId"]); + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_AncestorsDescendants) + { + // When the focus is set to an entity, all its descendants are in the focus subtree while the ancestors aren't. + { + m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); + } - focusModeInterface->SetFocusRoot(m_entityMap["carId"]); + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); + } - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), false); + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Siblings) + { + // If the root entity has siblings, they are also outside of the focus subtree. + { + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); - focusModeInterface->SetFocusRoot(m_entityMap["passengerId2"]); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), false); + } - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true); + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); + } - focusModeInterface->ClearFocusRoot(); + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Leaf) + { + // If the root is a leaf, then the focus subtree will consists of just that entity. + { + m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger2EntityName]); + + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); + } + + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); + } + + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Clear) + { + // Change the value from the default. + m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); + + // When the focus is cleared, the whole level is in the focus subtree; so we expect all entities to return true. + { + m_focusModeInterface->ClearFocusRoot(); + + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); + } } } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp index ffd6cd2a44..d3c3a2250b 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp @@ -30,88 +30,127 @@ namespace UnitTest * |_ Passenger */ - m_entityMap["passenger1"] = CreateEntity("Passenger1"); - m_entityMap["passenger2"] = CreateEntity("Passenger2"); - m_entityMap["city"] = CreateEntity("City"); + // Create loose entities + m_entityMap[Passenger1EntityName] = CreateEntity(Passenger1EntityName); + m_entityMap[Passenger2EntityName] = CreateEntity(Passenger2EntityName); + m_entityMap[CityEntityName] = CreateEntity(CityEntityName); + // Call HandleEntitiesAdded to the loose entities to register them with the Prefab EOS AzToolsFramework::EditorEntityContextRequestBus::Broadcast( &AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded, - AzToolsFramework::EntityList{ m_entityMap["passenger1"], m_entityMap["passenger2"], m_entityMap["city"] }); + AzToolsFramework::EntityList{ m_entityMap[Passenger1EntityName], m_entityMap[Passenger2EntityName], m_entityMap[CityEntityName] }); + // Create a car prefab from the passenger1 entity. The container entity will be created as part of the process. AZStd::unique_ptr carInstance = - m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger1"] }, {}, "test/car"); + m_prefabSystemComponent->CreatePrefab({ m_entityMap[Passenger1EntityName] }, {}, "test/car"); ASSERT_TRUE(carInstance); - m_instanceMap["car"] = carInstance.get(); + m_instanceMap[CarEntityName] = carInstance.get(); + // Create a sportscar prefab from the passenger2 entity. The container entity will be created as part of the process. AZStd::unique_ptr sportsCarInstance = - m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger2"] }, {}, "test/sportsCar"); + m_prefabSystemComponent->CreatePrefab({ m_entityMap[Passenger2EntityName] }, {}, "test/sportsCar"); ASSERT_TRUE(sportsCarInstance); - m_instanceMap["sportsCar"] = sportsCarInstance.get(); + m_instanceMap[SportsCarEntityName] = sportsCarInstance.get(); + // Create a street prefab that nests the car and sportscar instances created above. The container entity will be created as part of the process. AZStd::unique_ptr streetInstance = m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(carInstance), AZStd::move(sportsCarInstance) ), "test/street"); ASSERT_TRUE(streetInstance); - m_instanceMap["street"] = streetInstance.get(); + m_instanceMap[StreetEntityName] = streetInstance.get(); + // Create a city prefab that nests the street instances created above and the city entity. The container entity will be created as part of the process. m_rootInstance = - m_prefabSystemComponent->CreatePrefab({ m_entityMap["city"] }, MakeInstanceList(AZStd::move(streetInstance)), "test/city"); + m_prefabSystemComponent->CreatePrefab({ m_entityMap[CityEntityName] }, MakeInstanceList(AZStd::move(streetInstance)), "test/city"); ASSERT_TRUE(m_rootInstance); - m_instanceMap["city"] = m_rootInstance.get(); + m_instanceMap[CityEntityName] = m_rootInstance.get(); + } + + void SetUpEditorFixtureImpl() override + { + PrefabTestFixture::SetUpEditorFixtureImpl(); + + m_prefabFocusInterface = AZ::Interface::Get(); + ASSERT_TRUE(m_prefabFocusInterface != nullptr); + + GenerateTestHierarchy(); + } + + void TearDownEditorFixtureImpl() override + { + m_rootInstance.release(); + + PrefabTestFixture::TearDownEditorFixtureImpl(); } AZStd::unordered_map m_entityMap; AZStd::unordered_map m_instanceMap; AZStd::unique_ptr m_rootInstance; + + PrefabFocusInterface* m_prefabFocusInterface = nullptr; + + inline static const char* CityEntityName = "City"; + inline static const char* StreetEntityName = "Street"; + inline static const char* CarEntityName = "Car"; + inline static const char* SportsCarEntityName = "SportsCar"; + inline static const char* Passenger1EntityName = "Passenger1"; + inline static const char* Passenger2EntityName = "Passenger2"; }; - TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab) + TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_RootContainer) { - GenerateTestHierarchy(); - - PrefabFocusInterface* prefabFocusInterface = AZ::Interface::Get(); - EXPECT_TRUE(prefabFocusInterface != nullptr); - // Verify FocusOnOwningPrefab works when passing the container entity of the root prefab. { - prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId()); + EXPECT_EQ(m_prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap[CityEntityName]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); EXPECT_TRUE(instance.has_value()); - EXPECT_EQ(&instance->get(), m_instanceMap["city"]); + EXPECT_EQ(&instance->get(), m_instanceMap[CityEntityName]); } + } + TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_RootEntity) + { // Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab. { - prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["city"]->GetId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_entityMap[CityEntityName]->GetId()); + EXPECT_EQ(m_prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap[CityEntityName]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); EXPECT_TRUE(instance.has_value()); - EXPECT_EQ(&instance->get(), m_instanceMap["city"]); + EXPECT_EQ(&instance->get(), m_instanceMap[CityEntityName]); } + } + TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_NestedContainer) + { // Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab. { - prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["car"]->GetContainerEntityId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[CarEntityName]->GetContainerEntityId()); + EXPECT_EQ(m_prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap[CarEntityName]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); EXPECT_TRUE(instance.has_value()); - EXPECT_EQ(&instance->get(), m_instanceMap["car"]); + EXPECT_EQ(&instance->get(), m_instanceMap[CarEntityName]); } + } + TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_NestedEntity) + { // Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab. { - prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["passenger1"]->GetId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_entityMap[Passenger1EntityName]->GetId()); + EXPECT_EQ(m_prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap[CarEntityName]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); EXPECT_TRUE(instance.has_value()); - EXPECT_EQ(&instance->get(), m_instanceMap["car"]); + EXPECT_EQ(&instance->get(), m_instanceMap[CarEntityName]); } + } + TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_Clear) + { // Verify FocusOnOwningPrefab points to the root prefab when the focus is cleared. { AzToolsFramework::PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface = @@ -120,54 +159,51 @@ namespace UnitTest prefabEditorEntityOwnershipInterface->GetRootPrefabInstance(); EXPECT_TRUE(rootPrefabInstance.has_value()); - prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), rootPrefabInstance->get().GetTemplateId()); + m_prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId()); + EXPECT_EQ(m_prefabFocusInterface->GetFocusedPrefabTemplateId(), rootPrefabInstance->get().GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); EXPECT_TRUE(instance.has_value()); EXPECT_EQ(&instance->get(), &rootPrefabInstance->get()); } - - m_rootInstance.release(); } - TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused) + TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_Content) { - GenerateTestHierarchy(); - - PrefabFocusInterface* prefabFocusInterface = AZ::Interface::Get(); - EXPECT_TRUE(prefabFocusInterface != nullptr); - // Verify IsOwningPrefabBeingFocused returns true for all entities in a focused prefab (container/nested) { - prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId()); - EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId())); - EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId())); + EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId())); + EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId())); } + } + TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_AncestorsDescendants) + { // Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (ancestors/descendants) { - prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["street"]->GetContainerEntityId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[StreetEntityName]->GetContainerEntityId()); - EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["street"]->GetContainerEntityId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId())); + EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[StreetEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId())); } + } + TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_Siblings) + { // Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (siblings) { - prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["sportsCar"]->GetContainerEntityId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[SportsCarEntityName]->GetContainerEntityId()); - EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["sportsCar"]->GetContainerEntityId())); - EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger2"]->GetId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId())); + EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[SportsCarEntityName]->GetContainerEntityId())); + EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger2EntityName]->GetId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId())); } - - m_rootInstance.release(); } } diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake index ecc7d17ccc..11ea5a0b38 100644 --- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake +++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake @@ -12,6 +12,8 @@ set(FILES AssetFileInfoListComparison.cpp AssetSeedManager.cpp AssetSystemMocks.h + BoundsTestComponent.cpp + BoundsTestComponent.h ComponentAdapterTests.cpp ComponentAddRemove.cpp ComponentModeTestDoubles.cpp @@ -34,6 +36,9 @@ set(FILES EntityTestbed.h FileFunc.cpp FingerprintingTests.cpp + FocusMode/EditorFocusModeFixture.cpp + FocusMode/EditorFocusModeFixture.h + FocusMode/EditorFocusModeSelectionTests.cpp FocusMode/EditorFocusModeTests.cpp GenericComponentWrapperTest.cpp InstanceDataHierarchy.cpp From 3635e5ed355ada79b1e362576116d3d6e1fef384 Mon Sep 17 00:00:00 2001 From: bosnichd Date: Thu, 30 Sep 2021 11:09:04 -0600 Subject: [PATCH 093/115] Put the ShaderMetrics.json in the @user@ folder, plus an unrelated #include path fix. (#4402) Signed-off-by: bosnichd --- .../Common/Unimplemented/Platform_Unimplemented.cpp | 2 +- .../Shader/Metrics/ShaderMetricsSystem.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/Platform_Unimplemented.cpp b/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/Platform_Unimplemented.cpp index ea6c6bc5b8..afa75d8333 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/Platform_Unimplemented.cpp +++ b/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/Platform_Unimplemented.cpp @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include "Platform.h" +#include #include class ModuleHandle 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 528d32e217..e11624a921 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 @@ -23,11 +23,11 @@ namespace AZ { namespace RPI { - AZStd::string GetMetricsFilePath() + AZ::IO::FixedMaxPath GetMetricsFilePath() { - char shaderMetricPath[AZ_MAX_PATH_LEN]; - AZ::Utils::GetExecutableDirectory(shaderMetricPath, AZ_MAX_PATH_LEN); - return AZStd::string(shaderMetricPath) + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "ShaderMetrics.json"; + AZ::IO::FixedMaxPath resolvedPath; + AZ::IO::LocalFileIO::GetInstance()->ResolvePath(resolvedPath, "@user@/ShaderMetrics.json"); + return resolvedPath; } ShaderMetricsSystemInterface* ShaderMetricsSystemInterface::Get() @@ -64,7 +64,7 @@ namespace AZ void ShaderMetricsSystem::ReadLog() { - const AZStd::string metricsFilePath = GetMetricsFilePath(); + const AZ::IO::FixedMaxPath metricsFilePath = GetMetricsFilePath(); if (AZ::IO::LocalFileIO::GetInstance()->Exists(metricsFilePath.c_str())) { @@ -80,7 +80,7 @@ namespace AZ void ShaderMetricsSystem::WriteLog() { - const AZStd::string metricsFilePath = GetMetricsFilePath(); + const AZ::IO::FixedMaxPath metricsFilePath = GetMetricsFilePath(); auto saveResult = AZ::JsonSerializationUtils::SaveObjectToFile(&m_metrics, metricsFilePath.c_str()); From 225d9d3b3c297101f359be5f3ddde0784675b0e5 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Thu, 30 Sep 2021 10:33:32 -0700 Subject: [PATCH 094/115] Fixes to unit tests after merge Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp | 2 +- .../Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp index 56b8190719..22bc7a494c 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp @@ -27,7 +27,7 @@ namespace AzToolsFramework // Calling ClearFocusRoot restores the default focus root (which is an invalid EntityId). m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId); - EXPECT_EQ(m_focusModeInterface->GetFocusRoot(editorEntityContextId), AZ::EntityId()); + EXPECT_EQ(m_focusModeInterface->GetFocusRoot(m_editorEntityContextId), AZ::EntityId()); } TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_AncestorsDescendants) diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp index fa431e79ec..14eee84b7d 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp @@ -173,7 +173,7 @@ namespace UnitTest EXPECT_EQ( m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId), rootPrefabInstance->get().GetTemplateId()); - auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId); EXPECT_TRUE(instance.has_value()); EXPECT_EQ(&instance->get(), &rootPrefabInstance->get()); } From aa8594b49101360f922642ec723394fb3afaa488 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Thu, 30 Sep 2021 11:19:23 -0700 Subject: [PATCH 095/115] Add a unit test for `XcbInputDeviceKeyboard` (#4393) * Use XcbUniquePtr to manage xcb resources Signed-off-by: Chris Burel * Add a unit test for XcbInputDeviceKeyboard Signed-off-by: Chris Burel --- Code/Framework/AzFramework/CMakeLists.txt | 3 + .../Common/Xcb/AzFramework/XcbApplication.cpp | 18 +-- Code/Framework/AzFramework/Tests/Main.cpp | 9 ++ .../platform_specific_test_targets.cmake | 7 + .../Tests/Platform/Common/Xcb/Actions.h | 27 ++++ .../Tests/Platform/Common/Xcb/Main.cpp | 9 ++ .../Platform/Common/Xcb/MockXcbInterface.cpp | 81 ++++++++++ .../Platform/Common/Xcb/MockXcbInterface.h | 81 ++++++++++ .../Tests/Platform/Common/Xcb/Printers.cpp | 33 ++++ .../Tests/Platform/Common/Xcb/Printers.h | 17 ++ .../Xcb/XcbInputDeviceKeyboardTests.cpp | 145 ++++++++++++++++++ .../Xcb/azframework_xcb_tests_files.cmake | 17 ++ .../platform_specific_test_targets.cmake | 33 ++++ .../Mac/platform_specific_test_targets.cmake | 7 + .../platform_specific_test_targets.cmake | 7 + .../iOS/platform_specific_test_targets.cmake | 7 + .../Tests/frameworktests_files.cmake | 2 +- 17 files changed, 492 insertions(+), 11 deletions(-) create mode 100644 Code/Framework/AzFramework/Tests/Main.cpp create mode 100644 Code/Framework/AzFramework/Tests/Platform/Android/platform_specific_test_targets.cmake create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Actions.h create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Main.cpp create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Printers.cpp create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Printers.h create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake create mode 100644 Code/Framework/AzFramework/Tests/Platform/Linux/platform_specific_test_targets.cmake create mode 100644 Code/Framework/AzFramework/Tests/Platform/Mac/platform_specific_test_targets.cmake create mode 100644 Code/Framework/AzFramework/Tests/Platform/Windows/platform_specific_test_targets.cmake create mode 100644 Code/Framework/AzFramework/Tests/Platform/iOS/platform_specific_test_targets.cmake diff --git a/Code/Framework/AzFramework/CMakeLists.txt b/Code/Framework/AzFramework/CMakeLists.txt index f6851f0ab8..59393d90a1 100644 --- a/Code/Framework/AzFramework/CMakeLists.txt +++ b/Code/Framework/AzFramework/CMakeLists.txt @@ -76,6 +76,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) NAMESPACE AZ FILES_CMAKE Tests/frameworktests_files.cmake + ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake INCLUDE_DIRECTORIES PRIVATE Tests @@ -93,6 +94,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) NAME AZ::AzFramework.Tests ) + include(${pal_dir}/platform_specific_test_targets.cmake) + endif() endif() diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.cpp index 7cbd9ae0e2..f57f4a89ac 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.cpp +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace AzFramework { @@ -17,8 +18,8 @@ namespace AzFramework { public: XcbConnectionManagerImpl() + : m_xcbConnection(xcb_connect(nullptr, nullptr)) { - m_xcbConnection = xcb_connect(nullptr, nullptr); AZ_Error("Application", m_xcbConnection != nullptr, "Unable to connect to X11 Server."); XcbConnectionManagerBus::Handler::BusConnect(); } @@ -26,16 +27,15 @@ namespace AzFramework ~XcbConnectionManagerImpl() override { XcbConnectionManagerBus::Handler::BusDisconnect(); - xcb_disconnect(m_xcbConnection); } xcb_connection_t* GetXcbConnection() const override { - return m_xcbConnection; + return m_xcbConnection.get(); } private: - xcb_connection_t* m_xcbConnection = nullptr; + XcbUniquePtr m_xcbConnection = nullptr; }; //////////////////////////////////////////////////////////////////////////////////////////////// @@ -65,10 +65,9 @@ namespace AzFramework { if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection()) { - if (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection)) + if (auto event = XcbStdFreePtr{xcb_poll_for_event(xcbConnection)}) { - XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event); - free(event); + XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event.get()); } } } @@ -78,10 +77,9 @@ namespace AzFramework { if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection()) { - while (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection)) + while (auto event = XcbStdFreePtr{xcb_poll_for_event(xcbConnection)}) { - XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event); - free(event); + XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event.get()); } } } diff --git a/Code/Framework/AzFramework/Tests/Main.cpp b/Code/Framework/AzFramework/Tests/Main.cpp new file mode 100644 index 0000000000..c88648458a --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Main.cpp @@ -0,0 +1,9 @@ +/* + * 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 +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Code/Framework/AzFramework/Tests/Platform/Android/platform_specific_test_targets.cmake b/Code/Framework/AzFramework/Tests/Platform/Android/platform_specific_test_targets.cmake new file mode 100644 index 0000000000..7a325ca97e --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Android/platform_specific_test_targets.cmake @@ -0,0 +1,7 @@ +# +# 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/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Actions.h b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Actions.h new file mode 100644 index 0000000000..1650ff4f8d --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Actions.h @@ -0,0 +1,27 @@ +/* + * 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 + +ACTION_TEMPLATE(ReturnMalloc, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_1_VALUE_PARAMS(p0)) { + T* value = static_cast(malloc(sizeof(T))); + *value = T{ p0 }; + return value; +} +ACTION_TEMPLATE(ReturnMalloc, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_2_VALUE_PARAMS(p0, p1)) { + T* value = static_cast(malloc(sizeof(T))); + *value = T{ p0, p1 }; + return value; +} diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Main.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Main.cpp new file mode 100644 index 0000000000..c88648458a --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Main.cpp @@ -0,0 +1,9 @@ +/* + * 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 +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp new file mode 100644 index 0000000000..64c3967fdc --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp @@ -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 + * + */ + +#include "MockXcbInterface.h" + +// The functions defined in this file will take precedence over those defined +// in the real libxcb.so, allowing the test code to use a mock implementation + +extern "C" +{ + +// ---------------------------------------------------------------------------- +// xcb +xcb_connection_t* xcb_connect(const char* displayname, int* screenp) +{ + return MockXcbInterface::Instance()->xcb_connect(displayname, screenp); +} +void xcb_disconnect(xcb_connection_t* c) +{ + return MockXcbInterface::Instance()->xcb_disconnect(c); +} +xcb_generic_event_t* xcb_poll_for_event(xcb_connection_t* c) +{ + return MockXcbInterface::Instance()->xcb_poll_for_event(c); +} + +// ---------------------------------------------------------------------------- +// xcb-xkb +xcb_xkb_use_extension_cookie_t xcb_xkb_use_extension(xcb_connection_t* c, uint16_t wantedMajor, uint16_t wantedMinor) +{ + return MockXcbInterface::Instance()->xcb_xkb_use_extension(c, wantedMajor, wantedMinor); +} +xcb_xkb_use_extension_reply_t* xcb_xkb_use_extension_reply(xcb_connection_t* c, xcb_xkb_use_extension_cookie_t cookie, xcb_generic_error_t** e) +{ + return MockXcbInterface::Instance()->xcb_xkb_use_extension_reply(c, cookie, e); +} + +// ---------------------------------------------------------------------------- +// xkb-x11 +int32_t xkb_x11_get_core_keyboard_device_id(xcb_connection_t* connection) +{ + return MockXcbInterface::Instance()->xkb_x11_get_core_keyboard_device_id(connection); +} +struct xkb_keymap* xkb_x11_keymap_new_from_device(struct xkb_context* context, xcb_connection_t* connection, int32_t device_id, enum xkb_keymap_compile_flags flags) +{ + return MockXcbInterface::Instance()->xkb_x11_keymap_new_from_device(context, connection, device_id, flags); +} +xkb_state* xkb_x11_state_new_from_device(xkb_keymap* keymap, xcb_connection_t* connection, int32_t device_id) +{ + return MockXcbInterface::Instance()->xkb_x11_state_new_from_device(keymap, connection, device_id); +} + +// ---------------------------------------------------------------------------- +// xkbcommon +xkb_context* xkb_context_new(enum xkb_context_flags flags) +{ + return MockXcbInterface::Instance()->xkb_context_new(flags); +} +void xkb_context_unref(xkb_context *context) +{ + return MockXcbInterface::Instance()->xkb_context_unref(context); +} +void xkb_keymap_unref(xkb_keymap *keymap) +{ + return MockXcbInterface::Instance()->xkb_keymap_unref(keymap); +} +void xkb_state_unref(xkb_state *state) +{ + return MockXcbInterface::Instance()->xkb_state_unref(state); +} +xkb_keysym_t xkb_state_key_get_one_sym(xkb_state *state, xkb_keycode_t key) +{ + return MockXcbInterface::Instance()->xkb_state_key_get_one_sym(state, key); +} + +} diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h new file mode 100644 index 0000000000..ecda005830 --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.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 + +#define explicit ExplicitIsACXXKeyword +#include +#undef explicit +#include + +#include "Printers.h" + +// xcb / xkb do not provide definitions of these structs, but the tests need some concrete value for them. +struct xcb_connection_t +{ +}; + +struct xkb_context +{ +}; + +struct xkb_keymap +{ +}; + +struct xkb_state +{ +}; + +class MockXcbInterface +{ +public: + MockXcbInterface() + { + self = this; + } + MockXcbInterface(const MockXcbInterface&) = delete; + MockXcbInterface(MockXcbInterface&&) = delete; + MockXcbInterface& operator=(const MockXcbInterface&) = delete; + MockXcbInterface& operator=(MockXcbInterface&&) = delete; + ~MockXcbInterface() + { + self = nullptr; + } + + static MockXcbInterface* Instance() { return self; } + + // xcb + MOCK_CONST_METHOD2(xcb_connect, xcb_connection_t*(const char* displayname, int* screenp)); + MOCK_CONST_METHOD1(xcb_disconnect, void(xcb_connection_t* c)); + MOCK_CONST_METHOD1(xcb_poll_for_event, xcb_generic_event_t*(xcb_connection_t* c)); + + // xcb-xkb + MOCK_CONST_METHOD3(xcb_xkb_use_extension, xcb_xkb_use_extension_cookie_t(xcb_connection_t* c, uint16_t wantedMajor, uint16_t wantedMinor)); + MOCK_CONST_METHOD3(xcb_xkb_use_extension_reply, xcb_xkb_use_extension_reply_t*(xcb_connection_t* c, xcb_xkb_use_extension_cookie_t cookie, xcb_generic_error_t** e)); + + // xkb-x11 + MOCK_CONST_METHOD1(xkb_x11_get_core_keyboard_device_id, int32_t(xcb_connection_t* connection)); + MOCK_CONST_METHOD4(xkb_x11_keymap_new_from_device, xkb_keymap*(xkb_context* context, xcb_connection_t* connection, int32_t device_id, xkb_keymap_compile_flags flags)); + MOCK_CONST_METHOD3(xkb_x11_state_new_from_device, xkb_state*(xkb_keymap* keymap, xcb_connection_t* connection, int32_t device_id)); + + // xkbcommon + MOCK_CONST_METHOD1(xkb_context_new, xkb_context*(xkb_context_flags flags)); + MOCK_CONST_METHOD1(xkb_context_unref, void(xkb_context* context)); + MOCK_CONST_METHOD1(xkb_keymap_unref, void(xkb_keymap* keymap)); + MOCK_CONST_METHOD1(xkb_state_unref, void(xkb_state* state)); + MOCK_CONST_METHOD2(xkb_state_key_get_one_sym, xkb_keysym_t(xkb_state *state, xkb_keycode_t key)); + +private: + static inline MockXcbInterface* self = nullptr; +}; diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Printers.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Printers.cpp new file mode 100644 index 0000000000..9de17bd776 --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Printers.cpp @@ -0,0 +1,33 @@ +/* + * 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 "Printers.h" +#include +#include + +namespace AzFramework +{ + void PrintTo(const InputChannel::State& state, std::ostream* os) + { + switch(state) + { + case InputChannel::State::Began: + *os << "Began"; + break; + case InputChannel::State::Ended: + *os << "Ended"; + break; + case InputChannel::State::Idle: + *os << "Idle"; + break; + case InputChannel::State::Updated: + *os << "Updated"; + break; + } + } +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Printers.h b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Printers.h new file mode 100644 index 0000000000..0659ec6eb1 --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Printers.h @@ -0,0 +1,17 @@ +/* + * 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 + +namespace AzFramework +{ + void PrintTo(const InputChannel::State& state, std::ostream* os); +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp new file mode 100644 index 0000000000..1b494c9525 --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp @@ -0,0 +1,145 @@ +/* + * 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 "MockXcbInterface.h" +#include "Actions.h" + +template +xcb_generic_event_t MakeEvent(T event) +{ + return *reinterpret_cast(&event); +} + +namespace AzFramework +{ + TEST(XcbInputDeviceKeyboard, InputChannelsUpdateStateFromXcbEvents) + { + using testing::Return; + using testing::Eq; + using testing::_; + MockXcbInterface interface; + + xcb_connection_t connection{}; + xkb_context xkbContext{}; + xkb_keymap xkbKeymap{}; + xkb_state xkbState{}; + const int32_t coreDeviceId{1}; + + constexpr xcb_keycode_t keycodeForAKey = 38; + + const AZStd::array events + { + MakeEvent(xcb_key_press_event_t{ + /*.response_type = */ XCB_KEY_PRESS, + /*.detail = */ keycodeForAKey, + /*.sequence = */ 0, + /*.time = */ 0, + /*.root = */ 0, + /*.event = */ 0, + /*.child = */ 0, + /*.root_x = */ 0, + /*.root_y = */ 0, + /*.event_x = */ 0, + /*.event_y = */ 0, + /*.state = */ 0, + /*.same_screen = */ 0, + /*.pad0 = */ 0 + }), + MakeEvent(xcb_key_release_event_t{ + /*.response_type = */ XCB_KEY_RELEASE, + /*.detail = */ keycodeForAKey, + /*.sequence = */ 0, + /*.time = */ 0, + /*.root = */ 0, + /*.event = */ 0, + /*.child = */ 0, + /*.root_x = */ 0, + /*.root_y = */ 0, + /*.event_x = */ 0, + /*.event_y = */ 0, + /*.state = */ 0, + /*.same_screen = */ 0, + /*.pad0 = */ 0 + }), + }; + + EXPECT_CALL(interface, xcb_connect(_, _)) + .WillOnce(Return(&connection)); + EXPECT_CALL(interface, xcb_disconnect(&connection)) + .Times(1); + + EXPECT_CALL(interface, xkb_context_new(XKB_CONTEXT_NO_FLAGS)) + .WillOnce(Return(&xkbContext)); + EXPECT_CALL(interface, xkb_context_unref(&xkbContext)) + .Times(1); + + EXPECT_CALL(interface, xkb_x11_keymap_new_from_device(&xkbContext, &connection, coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS)) + .WillOnce(Return(&xkbKeymap)); + EXPECT_CALL(interface, xkb_keymap_unref(&xkbKeymap)) + .Times(1); + + EXPECT_CALL(interface, xkb_x11_state_new_from_device(&xkbKeymap, &connection, coreDeviceId)) + .WillOnce(Return(&xkbState)); + EXPECT_CALL(interface, xkb_state_unref(&xkbState)) + .Times(1); + + EXPECT_CALL(interface, xcb_xkb_use_extension(&connection, 1, 0)); + EXPECT_CALL(interface, xcb_xkb_use_extension_reply(&connection, _, _)) + .WillOnce(ReturnMalloc( + /* .response_type =*/static_cast(XCB_XKB_USE_EXTENSION), + /* .supported =*/ static_cast(1)) + ); + EXPECT_CALL(interface, xkb_x11_get_core_keyboard_device_id(&connection)) + .WillRepeatedly(Return(coreDeviceId)); + + // Set the expectations for the events that will be generated + // nullptr entries represent when the event queue is empty, and will cause + // PumpSystemEventLoopUntilEmpty to return + // event pointers are freed by the calling code, so we malloc new copies + // here + EXPECT_CALL(interface, xcb_poll_for_event(&connection)) + .WillOnce(ReturnMalloc(events[0])) + .WillOnce(Return(nullptr)) + .WillOnce(ReturnMalloc(events[1])) + .WillOnce(Return(nullptr)) + ; + + EXPECT_CALL(interface, xkb_state_key_get_one_sym(&xkbState, keycodeForAKey)) + .WillOnce(Return(XKB_KEY_a)) + .WillOnce(Return(XKB_KEY_a)) + ; + + Application application; + application.Start({}, {}); + + const InputChannel* inputChannel = InputChannelRequests::FindInputChannel(InputDeviceKeyboard::Key::AlphanumericA); + ASSERT_TRUE(inputChannel); + EXPECT_THAT(inputChannel->GetState(), Eq(InputChannel::State::Idle)); + + application.PumpSystemEventLoopUntilEmpty(); + application.TickSystem(); + application.Tick(); + + EXPECT_THAT(inputChannel->GetState(), Eq(InputChannel::State::Began)); + + application.PumpSystemEventLoopUntilEmpty(); + application.TickSystem(); + application.Tick(); + + EXPECT_THAT(inputChannel->GetState(), Eq(InputChannel::State::Ended)); + + application.Stop(); + } +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake new file mode 100644 index 0000000000..aebd28222b --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake @@ -0,0 +1,17 @@ +# +# 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 + Actions.h + Main.cpp + MockXcbInterface.cpp + MockXcbInterface.h + Printers.cpp + Printers.h + XcbInputDeviceKeyboardTests.cpp +) diff --git a/Code/Framework/AzFramework/Tests/Platform/Linux/platform_specific_test_targets.cmake b/Code/Framework/AzFramework/Tests/Platform/Linux/platform_specific_test_targets.cmake new file mode 100644 index 0000000000..e443831462 --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Linux/platform_specific_test_targets.cmake @@ -0,0 +1,33 @@ +# +# 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 +# +# + +if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb") + # This library defines local implementations of all the used xcb functions, + # in order to allow tests to run in the absence of a running X server. + # These have to be in a separate library, so that the normal AzFramework + # tests do not need to set up a mock Xcb interface. + ly_add_target( + NAME AzFramework.Xcb.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE AZ + FILES_CMAKE + Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Tests + ${pal_dir} + BUILD_DEPENDENCIES + PRIVATE + AZ::AzFramework + AZ::AzTest + AZ::AzTestShared + AZ::AzFrameworkTestShared + ) + ly_add_googletest( + NAME AZ::AzFramework.Xcb.Tests + ) +endif() diff --git a/Code/Framework/AzFramework/Tests/Platform/Mac/platform_specific_test_targets.cmake b/Code/Framework/AzFramework/Tests/Platform/Mac/platform_specific_test_targets.cmake new file mode 100644 index 0000000000..7a325ca97e --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Mac/platform_specific_test_targets.cmake @@ -0,0 +1,7 @@ +# +# 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/Code/Framework/AzFramework/Tests/Platform/Windows/platform_specific_test_targets.cmake b/Code/Framework/AzFramework/Tests/Platform/Windows/platform_specific_test_targets.cmake new file mode 100644 index 0000000000..7a325ca97e --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Windows/platform_specific_test_targets.cmake @@ -0,0 +1,7 @@ +# +# 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/Code/Framework/AzFramework/Tests/Platform/iOS/platform_specific_test_targets.cmake b/Code/Framework/AzFramework/Tests/Platform/iOS/platform_specific_test_targets.cmake new file mode 100644 index 0000000000..7a325ca97e --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/iOS/platform_specific_test_targets.cmake @@ -0,0 +1,7 @@ +# +# 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/Code/Framework/AzFramework/Tests/frameworktests_files.cmake b/Code/Framework/AzFramework/Tests/frameworktests_files.cmake index 680155d49d..6c4f611352 100644 --- a/Code/Framework/AzFramework/Tests/frameworktests_files.cmake +++ b/Code/Framework/AzFramework/Tests/frameworktests_files.cmake @@ -7,7 +7,7 @@ # set(FILES - ../../AzCore/Tests/Main.cpp + Main.cpp Spawnable/SpawnableEntitiesInterfaceTests.cpp Spawnable/SpawnableEntitiesManagerTests.cpp ArchiveCompressionTests.cpp From 5fe4d8043d70a23f55d081dcfd4097d45ebcec95 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 30 Sep 2021 12:55:41 -0700 Subject: [PATCH 096/115] set ed_useNewAssetBrowserTableView to false by default Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp index c6772ea2d7..acf935e6dc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp @@ -20,7 +20,7 @@ AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") AZ_POP_DISABLE_WARNING AZ_CVAR( - bool, ed_useNewAssetBrowserTableView, true, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, ed_useNewAssetBrowserTableView, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Use the new AssetBrowser TableView for searching assets."); namespace AzToolsFramework { From 6e115fb25730899472a0ccb1be6f1ea745276df8 Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Thu, 30 Sep 2021 14:20:05 -0700 Subject: [PATCH 097/115] Updated RTX-GI SDK to v1.1.30. Signed-off-by: dmcdiar --- .../diffuseprobegridblenddistance.azshader | Bin 90350 -> 77447 bytes ...begridblenddistance_dx12_0.azshadervariant | Bin 8186 -> 8258 bytes ...begridblenddistance_null_0.azshadervariant | Bin 486 -> 486 bytes ...gridblenddistance_vulkan_0.azshadervariant | Bin 8218 -> 8286 bytes .../diffuseprobegridblendirradiance.azshader | Bin 90394 -> 77491 bytes ...gridblendirradiance_dx12_0.azshadervariant | Bin 8646 -> 9034 bytes ...gridblendirradiance_null_0.azshadervariant | Bin 486 -> 486 bytes ...idblendirradiance_vulkan_0.azshadervariant | Bin 9394 -> 10002 bytes ...iffuseprobegridborderupdatecolumn.azshader | Bin 28300 -> 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 28297 -> 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 .../diffuseprobegridclassification.azshader | Bin 87855 -> 74952 bytes ...egridclassification_dx12_0.azshadervariant | Bin 6122 -> 6166 bytes ...egridclassification_null_0.azshadervariant | Bin 486 -> 486 bytes ...ridclassification_vulkan_0.azshadervariant | Bin 4898 -> 4962 bytes .../diffuseprobegridraytracing.azshader | Bin 160607 -> 142100 bytes ...probegridraytracing_dx12_0.azshadervariant | Bin 30714 -> 31950 bytes ...probegridraytracing_null_0.azshadervariant | Bin 486 -> 486 bytes ...obegridraytracing_vulkan_0.azshadervariant | Bin 32316 -> 34448 bytes ...fuseprobegridraytracingclosesthit.azshader | Bin 160617 -> 142110 bytes ...aytracingclosesthit_dx12_0.azshadervariant | Bin 13126 -> 13094 bytes ...aytracingclosesthit_null_0.azshadervariant | Bin 486 -> 486 bytes ...tracingclosesthit_vulkan_0.azshadervariant | Bin 5404 -> 5404 bytes .../diffuseprobegridraytracingmiss.azshader | Bin 160611 -> 142104 bytes ...egridraytracingmiss_dx12_0.azshadervariant | Bin 13202 -> 13262 bytes ...egridraytracingmiss_null_0.azshadervariant | Bin 486 -> 486 bytes ...ridraytracingmiss_vulkan_0.azshadervariant | Bin 6348 -> 6396 bytes .../diffuseprobegridrelocation.azshader | Bin 91763 -> 77960 bytes ...probegridrelocation_dx12_0.azshadervariant | Bin 8006 -> 8046 bytes ...probegridrelocation_null_0.azshadervariant | Bin 486 -> 486 bytes ...obegridrelocation_vulkan_0.azshadervariant | Bin 9298 -> 9442 bytes .../diffuseprobegridrender.azshader | Bin 231825 -> 203892 bytes ...fuseprobegridrender_dx12_0.azshadervariant | Bin 29467 -> 30799 bytes ...fuseprobegridrender_null_0.azshadervariant | Bin 589 -> 589 bytes ...seprobegridrender_vulkan_0.azshadervariant | Bin 20213 -> 22565 bytes 40 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader index 596f9a383eb7adc32a15e4712b7238c0188e8246..31fae5d98bb261ee35faac2489e4138379a5b952 100644 GIT binary patch delta 3899 zcmeH~Uu;uV9LMw1t}L=~*BPO7bh`_%sR{R9Y0buPD+qB#lC5qd5}jRJ{v<=CGACJ# z4;z@2Eh^<_@J48GCcR5Hp2vnCK?~? z)A{}G@7&+{<(zMR=W{ZX1(BQJZe%pp5A5)PA#6NMM*W*Rt$P=^^l_fze9MP!Vw4(hA8pcIj z9;l(+p!y)v?^a`Oz)r8QYZh|x#T5*X*P`T1h-oU-Vxdt~6?khOrJutC0CxK`N#q@u3sphZRT{RmcMsI2Ko!x|EkVJTBw(P6e6IdAZZiAX8~9 zyd2ApD@^MkE55m`6@Jk+zhdZ8>vh;%gN2j7e>^(%NWnn_PnKiKbviFCL-2WN{e#kC z@$J;1Tfd#5Y*T_%v=&RRtmA52G4^~D$y9hMJbJZjRpJf(%HHA!@2x?k-D~s{BklPX zmv3=@x5Z86rIo)u|ApK0ue7+6v-I9|#XX|GJrgRmy?!r(Gg{o(`%d!bdK~YV38Zgv z5bEnR$2$_8!wfA_o!jtlCp+^4r-#S0WXBOu+88Sp^KPR%F;5Vluoo#$_=5C=Eoe{J zIpPbVCi(e<Sci-I+(%WBpX620^KG5Hp*=S?Q0BL^!aMCX9 delta 6120 zcmeI0Urbw79LG5b2yW0825US1l)%7j&|9Dxe+T8yNRfXX12Yqa(hU-nv5r3z7n2b) zhl>ks^4+{92B=DWmy^LvL(Ks--l#a4uErJs7GNGr?fj~txEc>EF=QI2!AqT#BJ!(6GBP2iNO9c|hY)R#J72$sRHpohgW zz-IUro#@rGB&b#UVOz|>m;92S2kqDApjAJJ#Vf?c9X#f+ji zmI-_oWBH5~VwvCVJd=r(8smGrdA(nsfRXb#xcUNdXx=MW%-|iJKMmCdsY)lhHOz>{ zG(oh-G8-0B`J-zq;aL)Vr5ExUlHU>dsM9f9&*!>Y;BPJ!_DmyOyqn;1GlGYtr`KYH zkHK@XUUX_%m>9O3y@C1~fxpqinEY89jWqfBJ7PklpS8w$?KlkGN7+uWfQkRBqI676 ztR_w*P9!!E8;G-rvxrT^CSo(OnYe(sfVhOXgxErCA+92>BDNA+iR*~#h;76+;%4Gz zVmq;&*hB0go*01LN``a)q_T3Am8+~=W~T-8uUNUhlBS|i zIeX$!?q1Qmhh@jpzUg+YOb%rq(R>vAivhr5(ytt4wDS^u-idRAGrN}^U0^?y83N4=k{UvZt#pAEU5n8b=TKH+u-OCJ8a za_t+NeQQmu`KN&wrn|-P*Qv3(vyQWI-Lpk?1X~yFocTUD@1}9dHq$MeqAiszPsz6D z!Mbec%(t(pW)_!jsr00JpQx53+ceLGn#^17aEpD*6`KaWRwfIV`A;S;S8lO!Ir2>% z*Te9jlPkFt!P82fx-iOhT<&09$))%Mwec9WXxG%-t>bF${C2CF^D_lLQ?j1R%_UQo zHGQMJq3d!@pu)JO?Q&~-N(cb^sNH_9^2+Afsoyj)b;(fA?e%W GHO(J_{C1uI 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 8481bdb15bfb4b6e4cdf4329b8539d31b98fefb1..19e9fdfc8d23db9d1ac4b062b395258ab3eeb219 100644 GIT binary patch delta 4032 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 delta 3931 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 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader index fc11f9de64abcf032720d6e9712b883fb705b387..0025388bc13bae5830f46f3b79be2b4a3a0800ba 100644 GIT binary patch delta 4099 zcmeH~U2Icj7{_@=*{0ahgM6G8x0bOF8Cg%amME@ZVRMY&wz_dK6zy8UWFoZLCLxQ_ zVRg#{*RKC=G zd{1>47wxDYG0-k_jd+l8I5DrQ(;`|X(r#?tWcT@&LbsxjTs&9}%d{rGFxTNH5k10d z?$)8;h=`CV*I9wsIWvA8ji>SX^3m|VNEi5vofL-9>0?z3$pr6c8CH2#A>uiRll;2N z>y;-oWI&gBE4-CTywG(U)`-L_t-@wh3Ycm!mBQ99vEhZpyMIy7o_>T5z!v7Yx2fT(<$IMa z=U1l9>=U{o2DF}1V84GI@3|EldnI3PDf*5|uuLus+A?Sjp@A0_JC}n|zaG(NCBBEN zQF2Vr-V}&`OGP`_^;DA3>ds_Vf%N#HUxKc#5+zK6b!`>Kx+O@r)*!Z4&n6z`kr@MJ zDN7chf5?=6amTHdA57H#gztuW(!1Yk$SGe}`ULYlMp^jUcrq!-q#*wjg8Xtj*#g<$ zUZy$o%VmXCREUp;RtDRvNJr@hGEA+;Sd%qy^%do#_f>A7vZXC)qe&b67i?6E-s7Jp z#h5(PANZO64=nVdnxlPQbNhMkg5arYDiH!#uH}*N#@|6{$92c7n+9SxUZ;DKC>t!M z`6z0_;G}*AN9Az|vk0V`d zT5sOPrPH%qI?hL9zw6^{D#y%cQ=?qxU-`6^84Pqcm<~+Mfho^14@{@+zTD+Zl|mwg znZ1bOgnCe>Q>Hdj98cLNM*5RapSv07Q+C2c|9e1PpJw>x`9n2VrsI72)ia@vqT`FN n%6xh@smr7;AJ~u6y>%Jn9&1jy52F6KGioTV_BYD*x>xuE59Hca delta 6430 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 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 2f2cd5cccff43f5abd9e32854ad3bbe7a994c792..4a2b0e9944d9b41fe3c3c98f4c7607eebe0d3a2d 100644 GIT binary patch delta 16 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 W(bP{r>~i101liwyG^HzFwtoYb$*W8N literal 9394 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 PifleFYAraqKidERu9p1D diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant index 76f61d2fd4b8b32be070bc090959f040d5239c48..f60c7135977ac8215b5c78551c6f716448afb590 100644 GIT binary patch delta 640 zcmZ3byh?dP2P22_d;uNCpnRsu6BvCAKhHmVOl0v?=17k_P4n41OBfj#7#jE)7}$Wc z1rU1xaRd-&0Pz_h=GiRBbe&z(CBoAuhn;~TiGh{jHc$_U&jh3efJ#Du;!e&7?kVyx zFkG5^k!jE7mt40PZ$c6qw#hG8{4ns;`t_VDO#%kSB_bO>l;S z$Jxn_yrT8n(wR5;oZZC3wn1@$nLtAbqc98O4Tc;EF`nB3Dbj5ZFL`k8Jvnje$KkDG45u&b;O2U|e$IXGf4d1YC73u)&Jy5PnaFH-L#>CW!;xc;U^6p=qd~)? z2bZrUm?$!E!L?1EE1<|IHF>{)n8#^mjl>4QW;US0h<^`w&oS_|Fz`J9B9IO@;g$rG zL;*M9j>IDeKo-sloWX3S&}_1TIZ2?&T*JtMS;8=bL4c)s>10_!B}UK54uVM>bHB=Y IYy!qJ0QEJ|=>Px# delta 642 zcmZ3byh?dP2O~!g@8(;njcS`GPhj*hH4D7=SXy}HSy!9iD-}3Q`xqG*7#jE)7}$Zd z4G{YPaSRaW0PzJN7T{oD(Amt(be-MR!!g)H1SkXo^Cvd@Kkd33d-tp7_VY2e$6O*j zeSCmsBr&iuTn3s6;xhqh0iaqFptzIsfqRNP3=F3>^KwmNl3NY+`~l6g*nl&wTK?ASj)imAjZia z{EO=&+XP(Cb~rLMC`kBRSM-={)n8#&ijl>4QW;US02#1Hf=NR}}82BCl5lDxda7%(o zqJW!lN8*tKAPc2}W-yy6G@GnoP7-J`*D$hRmN3j<5MXIOI$2gwi7{}pgJ2Rc$v^-A Dp@`27 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 2f2cd5cccff43f5abd9e32854ad3bbe7a994c792..3e810bcfb51b320702134c14db816f744549bb72 100644 GIT binary patch delta 16 YcmaFH{ET_SJw}eXU*$YDF)%Oy06p^t6aWAK delta 16 ScmaFH{ET_SJw^@&C;$L0bOUMt 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 8b6ec377a6d8ae0be62e2039f4c523877998bd75..5918f277b577ebd0685c1b784ad68aa7808ff1fc 100644 GIT binary patch delta 16 XcmeAb?G@e7%EdAFtDMIs1_lNIG6V%S delta 16 RcmeAb?G@e7%EiF|1ppz10*n9v diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader index 9050f9094343d831346b79bd14a9c614d43e3c44..120eb70e545519f0872beaeb7ff920804a40ee2e 100644 GIT binary patch delta 478 zcmeCY%edz{;|3)b*12EheK%}YXW?fQEO)We4=BpdN=+^)*3UOiNu503z=+MoxgfyL zW%Ea#qs(k493A2;88AY#tQ zG3AiqQDcd-n>X`|@e1QLc=AUc<;}kg7NIz4^8>ww_~e3?|QuTrv4;&}Om?*gP-t3ihB| Q5H{bc{T3oF31B&vqQj<%H_4AEWQsawD3sQ^95{ohu z^GYV$^BA#3MCD}$xo)m!J<81L;ph-&x!F<2nUU4QvtVP&Y)U<)Voe^}R`8!Wi!!LqAUe;;YsEEs9Q$dNSfTWo>R zrpC<*qP)VyyJB)ZtMcZV8jEoGYjdOS5)y)lka56ZBGF@D|%l$c><%4;VB9CMl%P;S#7PGE0*l`4`gIuU^v0Yz`zEi zEr8eqh$DbF1BlN6G0SE_rt|EYE)kwSdw^<^7+4wB1NDITOh8%ysALIH+{yXCJw+Y{ zhGmm4GVR&?kn0wsTx$T2GJ|TMfQmaqhqyw50@GVbhC{|c^_3C~3_g=@@XP zILne4Va9QKb7JI-v`Dr?g)$k=0=@#<(wR5;oZZC3wn1@$nLtAbqc98O4Tc;EF`nB3 zDbj5ZFG+CjJvnje$P-HBb+$RvjG54#y J?*?GV0|4={u7v;q delta 524 zcmeyQ_(^d?2P4OAx3D#mzl1kWp1|m1s=76=?azk)Z<#AwvPC9+>}6zNU^v0Yz`zcq zZGhMZh+}{_2Z%2KF$V_&gUV)Jrt|Es9*)5tB0wP!cog)zeu|h-7N36PW~<94`&=SC zede$+FeEXsGAsw03F0#WX#t?x7NEG3^MQMcJPZu;CZA>6v-u#`Ek?Pe0X)hKs(~D= zjzugD6^u-5N*CraD%dbHR7wE#Pu|HBRWBwuL&4)5OJal>$LY<9ku%aF*$x%TWH<}> z3YcXy85l@UNX?p-x}bsAacd)k3ik{J4hH3g=9Zg`c4}E{GT3Fba{KOuD><3I`v|n9 z9o~?8m@Vm|MxJwH>Vd1FiOHL@i#?UKixSFfHdtv!3TP(&$E^Qk*8o_tzx z@6w$Y&z7;sZhp!8i7`I1L%{WHha*#if`m`FlE)94mOtQKFVxt3{43RC0u4n z1t6gdZ9G>qoESnDIC9EN3Gk40<~3)Lmf$fLV3L?3@J6RufMu&dpu3fRP6Q0K}K8TmS$7 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant index 2f2cd5cccff43f5abd9e32854ad3bbe7a994c792..6d7a604701b9a849b2be3939000072f11beb9371 100644 GIT binary patch delta 16 YcmaFH{ET_SJw}eXU*&x_FfcFx06q!^7ytkO delta 16 ScmaFH{ET_SJw^@&C;$L0bOUMt diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant index 8fb8e921175bc2cdebc030a8b9d3afa075d2a469..dee941cfae644d19cb161c0826cae0801f7b7d54 100644 GIT binary patch delta 16 YcmZ1{xK41xG7gTpU*&x_FfcFx05;$SlK=n! delta 16 ScmZ1{xK41xG7b&~C;$K^N&@8o diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader index b9552a85db240ae4b45afcd4f9492ac8421de7fd..e2e0fa90f5cb67db90fc3022210ada280ffb5e2f 100644 GIT binary patch delta 4323 zcmeH~ZA@Eb6vy*uJ4>L07LdDA)*=ja*!x^c)ohJ|8`(+}=md=>bEDlBGhJ*qkzkCK zL?oz7DE-e~JKvf)-$Q#%&2Y|aRmZ{-4WOAHT}|}UHcE5^GED1pdy91mZr{vI`t9VN z^PKmb{BAU&o;<6Ps#WT@=S>zGt5X#d-E*xQsq=v6$vwMzpP`+0R>!TwJSqSr_a;`ANF zkkRf7t_9u5!LM~AUbF$>7kiQL)xaDvz})HpowEldH-wHVm>fG=jx(x?gIV72E zK2?Vk16*Lxjdy?F1XHOS$@|(6Ep>~MhSVY6%;Ch#1|$j{m_DsX`0{%4D9GR_OU_m7 zV#)E?KBVZq^(F{q9NCRgtqcBPy;yQHDaYysj(G8z!-bt8GkzZ8zz@5btOZ?cz|^pu z=O849;>17POis(L#p!xtA(PD48VvMQLC`iJ{z@Y{mTZ~A6I^59ct8GpwGw8BpM5qE z0lyS(MZ&0ssqG5R*U)Urdc;#aeC?F!&O+*@a!)bhCh~7rRi_I$17i=O-?c9oVAQMBA zo!iqOM)v-06}}2Ku>L#o+9;I^EEi|hEb0Z&akGuwLlB;jlYR&SvyT^5Bi+S|z5+t! zX>?;YC1;^$11=Pu1?-{aFon0i9qA6rI@*CEKV=iIK{~{XQ#Y|>PR`$o^zA%^kP5R$ zteP|3ixr`%uHT@Wd0q3t!aHZa8+sxxj+BwL@LD7JP0erW4ZW$c$js*?cPZE5;Exu} z9jO?9tCg6E=F9J|nD_QrcEsM?r7gYYGRIPVHR_zB{K?Iq-2eRKn(*s;WBD!3gTW08 z2G=>awxut|9(%t;img89*6W_X4&{CrFDJ_p+fbZ3tiDvt%pFcCn>^ zl;DDo%Ob8JW01kzj2_adk}T>fZ*#b7L;Q~xhIDrZ1{IZpyo#(~uWYg}L%h!9KZ*D2 z1s9Tffl;q4EmN;-^EdU1`;BA;>}|^AmqTAA+ST}LK+okCc)A$bEpizYmOU#d%;H^* z!b-sk3ispumde0!#iz8?$WWNk@w}bEZFLrjwSguejdS{*?E delta 6045 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 delta 2467 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 RpG#j_N%qfQEnUIn{tcn&xE}xj literal 4898 zcmbuDYj9NM8OKiufkZGs1w)XM1?wduAwmEzwYkCuO~@u2kU&g0Y)+Duy@cIO$THfN z)((-e!tkLCYFlVKrGg!>by{&4dvS(I#g0>ZF=eJ-Xg<_VwazfsLTl~+clNx=X(pY1 z=<7WDzR&-;ywB}DII%3t${)#VeQj*f`mx&LBOjE#@X1j3tE0a;`pCMxv(-GB}FNj>da_;#3 zg}2uZUu{}3ug~f%-|+jZ(-bpb87+BzwD@O#SbQ+?L3_>D7H2CzKlJ0^ey;xh#~pk2 z?%P^=tnEVW;qmgw{B!v;Zk=sec`9eIwcji10&9kg%&}&judh8iJd*C1Zner@=`_ zf}yR#$PgJTnTqyB6JR-g>X8_XE3b6ONrlMKy$gM6=Vr|f;Q>1mP4o$xkW*(@-fR!c zK|_>eR2$=)9!%KRCkGRmv}8qYEY#eU8LN%M1IdJwP^uI5)Zf)<%%(F=%1K8j?Ww&h ztM9iHeNKD7#Qn)wk6_u~;NC$WT%9^4-JeM~>GTx6Ij$c4aP>B)Qg%<295yB*$sVN} zwBvC*=X0*BOI>ohi6JMIcK(}*iD8b>-!d4V)NOZ$ofzXVQIEMkJyQ~+HOtM&vTl@4 zBAJTYvAU=&Yl9aHABsBrawvGA8|ysdbDN!t+Ph;;$nN0*nb`Q0xw)u$ZAndNG?~zJ zC(^yT#MR6B;r$G`Gu50Na^h-IyI#xWJ^F~{{DdQ^WGvRw+naXOYTc9T^-V@zXGiw* z>h<`#U}9Nlbef}yO{ruegPtjbWM+mJp=bBd8(~;m*3FaHJvwUIi!ACs&3nqdG*@Tl ze|$57`eHE8*ew;oGr#bk_IT!Tg@}b5e!0u#c;?M7heysELmyv$IXrUS8FFR-pY)~C z_hxSu&oUVPz|c1sKEV98t%39QD4kv~|24AT%=!e4~UqJl^#z{EW?u%`i3VTzdpHe7jk@)hgOZ@$>G`K=c^4*{D&`Xi5Y(- z;sYWhU#v6B$V+wR4&q&+Js@Hshrh+;CVA$T_)1j;dP7X`#Ap_0uz-Bm2pfpSJ&(&5_1YjpUaJhK58q2-<&E+#xig^sJ`u83 z#YesF7h%gX*aJF);oo3e zHj8RR$mrig+F92XFS3V4VDymlHSP2m9{iA3hbEnCMAYV>hc)}KkTCkYMT9OgdcIP7 ziwK;aGwUId$;sry?6-QdXXFdM&BOTq8Z7MLe1q{vKiWmcpTE9aJ=t9Kjoxe%F&E4~ zGQQK~`-pb(W&hCA-L5lzr3M|M9U^2mYTqg1n~$thWMtg&sL0rLd9s(3554I2iyA|B4BuDf-{ca6x@HKH>(^H89@N5pqww|Rl>uQ z;>jT?A|AsJ=u96+yqfNHW%_?|?aU?L?3BpNWvR~e314YXW@?`ik3IM)uOEXt69Y2( zF{GVEKalMcfl+JD_@1qOSX3yA$Pech(JdmD|7~MyY_d8V8_w7)6|wv_RpLKZC-0@3 z+o$_GhQ2c|myI3_9r)_Wimp)QxyPLS?_DYQqzm2r(`TwXgFAY^apAYun|~Poh4)tq p*UwZLH&6dZ9xIz%ckRxBv2T6p)+ubt%d*q diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader index 66895758deb7e247b3d554cba2bc979a4ce886da..2c403c77f88b4e7213022796f694f866ba71160a 100644 GIT binary patch delta 4723 zcmeH~Z%k8H6u@^cWh+r)sW=|(kiX)D(TBhU3W7xgbP{=;UsxtsI>>Zkp>b>z|FzEj z`7#OVksbksE`*7bj>5}QQD!QW#C_4~<}_On{ID%q7G=p266411>mTSyB>O-@vh>q? z=l(tC+;h+UovB}QvCCeh6Z5GQ3FbcB6am z-((X7PlQaIGLFPNdtJA!u8=^9O~9k0q!GN1&7z>%FNg2P;;?Fh#KVna=V531erUfF zBPP%8UKN-kme}4UpeT!`2by6xArXJSOjO{ymjc#=bTsDDE#OU1fhVUD1uIF0rc)eT z>}atWR-r48a!_qop*fPA0RFTIlk_wJ^6eb_c-mxtlW5^krwL{T(lIHY4duE_FkO*> z%>_*OqRWKS`-mR2-O>;xPFqPVt|_D(T8pR(tc4$v8i-NX!{GrAOSP0Edwe2O6`I5- zyvdrtSge9=MHbS4$BSq#m|HYxUQJ4g8S0BWp}fZg=CcLxYmd(Wunwhxria5h9oxXz z^9i};TT$y=2X(z1xz40`Xzy)>GmeAkH4`=PpB=R6)Yz<}dD7y{Pa4*#g6v6^B#Vx+ z0SZT*JX=}`4?C4G)UQEBE8)Sx)Qtap46Op?VW#{lTB_O4bVUs+;#l|LfpQdfQyIp# z5({|l%Rm^&l>E07JaIBuZ;t>;1O+z!tV^3Z0B6+O;W0)mT2M+=ET?=Ct7d-{3lJgZ?QiK*vz ze;G`&R;Gi}W+;Sgk%uG0ZhWL?dYjKiV|y`Oi~OrpW9OIwQzHiZIQ#mKBOj*?R0g-l za^%M1lCH;vZ8SEACh_0rv3-|-_GCbc*cFpMC%mp+kGTw2|%A(yYMgwZpP(v zJ|1^79?v8JaH*k;v}Eo_FVb20!e|#}Z=o8A#iAkOO9d1{m9Hg;d_ho0Zz-*ur*w4X z(&LQI^X6wWk_+K<)?LZKEfpLc9OLzcVL@p3wd`Zm?(Ygk_drVszvrQ%fWFW8eSYv_ zh)36bB4ug`jWb9MlJ7_;&im!XJnx@$raRvc^$s7)=lZP=U}z>I`@p6Fyq7Hh_nY8b zMq+3sT{TyO4K>zIl>Q6y$2~B5k|C-;$jLX-7 z&=)wIBg4^fx39|W-A-987A_0Kkh0+C#1FDwKe;typ)82(?Ed!2t()hhvS9q_ugFs_ zkyO-Ay@*0Z_=X5IDC`-mj(6`H%WTK++WqwB`XsBpHmZe4Gmq=8`h@y2Vqz- A9{>OV delta 7886 zcmeI1drZ?;6vsV3iz{MzW6DFVGUg^qi;xM*peVX3K8m^wAGCt7MYBLKk+=HNe5~~NYL5WtZS%Sy}o+&it75czW96MNCSxUJ>m&z=o#hF}5iUeNCGo12>zi$-Wpypl_QVdsn8RJaG&8 z+8`h0j2y+2NTbY1kuBXc?j0TXZ5g5tE@4bm-cd4KAKnGz~bXSr6^#e7{oG{D=2`G2jn2QEn z8t5hF_qg$zM8-v6ROXparo~{yZq(7IL!>kGafN7!wV?f8C+U`oPU4-6BdZ5;uxp(L zm(9pl);)t>m?wPJ`LGZTvyA+X@%V>@bf5`_lKdHDpsqeQTM#8H)_`YH3s=6xNing5l%Mcl!6SEnV3%j`&NlSh@#C4tKfL?dp3n9I z<^tv-<|1Y@vzfV!xs2JuY+;_wJe%3dY-L`^ypVYr^D<@^vx~W%xt-a~>}Kv{?qoj6 ze3IG6>|^d??qZgiWoAFKU$9<+LE!l{8-_?Ju&T->x>FC@XhsF2vix?s@MUmOgY`YD9L+5RdM20KQy zLS+F$J1Yt6g(TmHSHKmBC?XWn^#`zD=!3xrghfI!9TIQgA(b$V7pq8bxgotUVj7Oc zyV8T|VLxkFM-0xP=ym}`@km%r47|f`T*TlNI^SqjTvWwH76k{mxR~_S#rvD0e#?r8 zi%Az!pWSq|yG;=nN71x%@X>%xog`A{VQ;n!6;G-8GpFBOi<&>x%NcP&sa#X4moxwA i<;8L}%vM^y}qUJU5Tp;^~KRlIahdU@YYT 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 fd22ac4fd3160ef56189ffeb6eb179581c9ea614..4bcc47ee43a6bcc8c2b33f451d22a0b963981210 100644 GIT binary patch delta 17360 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 ?nUKhhg}(PAJj}?8$vHeJXR%dDDZ@FpQgQdz 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 M6I&Dt4H)qM06r6)`v3p{ delta 16663 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≈Jy|H2Ywd3wc(v}3V9(os0Ow9@ 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 BYDEA5 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 acfb2aa716cefa73d2c05ae61b45992c4d7851ab..93cfb4781977a009b6b4aa6ca9c5baacdcf9a5e4 100644 GIT binary patch delta 4594 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 V4tXx<{~f!Y+Iial!@H!({{fBa&=3Fs delta 4715 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 Lev6E2o4)=F8)W`M 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 0bf9ac53d74137223f9945e8c6d37f613db3440e..4a16e24211faaa39226db82f9bd88979700313f2 100644 GIT binary patch delta 16 YcmaFH{ET_SJw}do(5{8&F)%Oy05S{(Q2+n{ delta 16 ScmbQEHAicMh$sgG6aWArCIW5% diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader index fad06893e96dbaaf81d581f58b9d3081c49ff33a..d95fd5b3b2bccd1f9153241ab9ac8bfa7dad6a3b 100644 GIT binary patch delta 4533 zcmeH~ZA?>V6vsV}6{<^TdD*y>1?o%Zg3{Xt2AfK`Z0KM!QgLs|cu0liep4RQDP$5OcZCfFMeT5_Jv5?bKBcci8J97S<+9v z=XuUO_nfEybMkxc{<-qR4egLgv%=ri+L#*1)?`3ZeaU9g-q^6OZclTQ*pORW7wD=^ zNKLp_ELFbV%H~^&SQo)U8k*Y@z7_ zmWMOld+^o?C(R_lW<2O|lJ9-6;WNEXl0JZ!Xl@@kDWrumw0WH;m#rfu7$&N6n%_7UmFGWkU`TDFC{3| z;8?$#uNuga&rij7+DgG~Y}KU{@G=S=0Fh_Co*dhlxhI_)`ZMD=HN=0tI#HB(;M{IqtP&IRIv~tk#fGh6Fk_0w%QiUq-`# z7#Q*w07`a|+^Jjz8wLl_@fFX_2<2$pFOtR1UMEWnuYqSoK|8adakq#a7i8T2jTk-N zVjMrqBUG?m=>A(I{ccvWeD$(rI8vFbb!@fu&U)9`>BC>ZO72dm)jqiM;IpcX?>AB9 z9Au(g^}}Lyi=C#cflu0ZCC0TI*Y472H{icKv0R;%_~}RmrQ|@GTz(9UpuKnVVA<#F zpQ*reKi4NOR@?EJ9G}TcJd?91(G0_j6>fYem&So&X@TN#L;3X3ky~@V$x*o#;b_t$ z#cgL7kFZNgQ3B?;T)tAlWUlOVYR_a}Q}P(>oo9~VSPU=!HTh^>Hc;p~r>|IO_T79K zn)4zqDq-m{v0I2Bbl5S9&`uQ!^|+-+;3yq=E6UT{%4hYQr}M~Fz+6=I+dNN)_aq7# zAr;^A2r5~tiG}f+AfLtXb;O(pY}Iw1vUy_jl&$VAKy9_CC~qsJENqX+iwfE%#^)A$}WZ<~EejsUnuakvmVZY7`J}L!m!|gSh%71+HDm{3fDe`C5{$!?T>dbv-Gt zLk|89<#9HDn9cvlI+XKHXJK{>o3HSA$L~*0oK@KT>Y}?u=3O!yL*?-f3ExBG9rAy@ ly*{Qx(0{o`9@nr%fEVo&ny4{ delta 7835 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 wr~5100e_-IM=zh->4R&uEFT!y#od5s; delta 4967 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 delta 16 ScmaFH{ET_SJw^@&C;$L0bOUMt diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant index cf8bbbd82494b697e9f0edb4559340b081dc6260..34761ccf98ae556858256ecf25608fd87d6c67ed 100644 GIT binary patch delta 1132 zcmZ9L&ubGw6vt=MO|qM&ZMG&&e`#vB?Y6d}p$CNuR#DP}Qfqq<>cQA-C6Hu88WY4r z4n25Om}9`Bo`k{*J$TTA2M>bY#jD=*4^Xl1J3Fz118?WO&%BxU_B*>D^S|>4&$;>5 z|Fn5{d1FYt;069H_`$zLb1^o|7>kfK{ARIP_G{#_7&9gB6JO#vZirv>jEV_!g2%)K z)8TQkO};7G zQN_+{ET-5cjl~sP)tIT+HH}${t%a;33qw&9z7fJuO~r0$3~D29OJf6y-O(6yN8VkH zL36Ns8cVTG2um8Y$wy-SKZZ9fyq$??7X?B(T>SODpyc?4puBqu_f$ z#c*rb{6S+`#Xbiw2Mc`TFNKTDV3RaYlW`UI($F*3ar_J!ja9^0pC!W$eN9IgM4Tc% zC)QKTV=hG)ka3)T7)XcJdC^U+bQUPWPXsNpM9;{Xu|AqdDPE)*ts9aX@@qnU?CJG- zmVD$-QWo?;KG-R$2OY=B&?7i}>_;7%#dX^jx9!mk>L5pPnX@E1c95SViqkPxr~=*x z-C!V|rx`bgfp{U<8GanGPE&Z2Y+8IzKjDt>GlzU8a7X$%pB2klmxAqVnVYYkwi{^r E2qz1_gz9C|XDkitz_}v)v|(EY_qX@kj9x zQP6`24|5c(2k~lQg?jW4@YbVv_2@sKpzpgoYsZ1doA-J1e$3n1-_@_x-M3upHOo(5 zbnh&S54_ITgP;6Is->|UV=O_k)$49}^`76pvE{b>&Rs$*%_9Fu?7!kZzV2?X`u&01 zX?f(&gz?GPkN8X72c1Eme0u0hiL07DosLg5w)+FG=k@)A6B+SZv$-Y$&EdNErd7Bh zGWuygD$eN+9}{c3eeDp%ce=g%?&d|`?W41Fn0=i1L*IK8(Swc;$MtTxJ>T8f^qOva znOK?`VVo)UDR)-<(r0*195ZJ4gs2%d&xYPGNX>VDA++A=$3N@{)Z5 zE6LI03nBP3pkzhKz6AT@b?)L(R#=kZi=8C-qu2=L(zZyKNN@+7N9s8eS}U;OpC`fB z`JPWO3~-jXBkq}JcvLHL+@xw@ex}v0yKd u#@E4uy%>nxlZ1{TO_SKdD!k++u~XRNbHVN6DChH{WjSQLvV4v?gzGP7%6+8( diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader index b46a476221c29ba5256e057f090f56385e2ca546..c19020dc84df5e5bf3c02c1496d86967dce3966c 100644 GIT binary patch delta 4069 zcmeI#Urbw790&0HT+1NHl*ymlGD_S1Ng%AZWfvTC3zvUF0EHGFwi4-|tqYh*yIC3W zVXILS<6JEJZk)+df-fe5nXntjvKdfcbP35Wi4VM(u=wPI8Ht)W-H7MjUSM0)_+T`~ zKHYOqfA`#9&;8|>&-r1&{MK#Lbg9Xl`pNcAr{Xj{LHVyV?Gw9BL|=>?j=wBM_Z*3! z(_EEx)Ej9&KE%9EawsJ=S>~*->gB##Qf6k}ehk5~yzCRvcql#)9mMBfSg?H83fbC< z=>s)zzZpjGjatZ8<4An69UZb2YHlkQ{M(VL6HwU@X0b}DW^R!rB;Vpy&QwwM- z`Wyv_)eD%o9!8hF0`m>RsE0=e8&0yMHb|r+cOlRyKy9`n@p>zh_t6gAZxpB>?_VFG zV^}N>X?e0Ii5yrh)T0nAFN1nUpg0zrCn&*#EI9LQ0%~!X$&ZsAXIlhB=kTu59J zv9fI|ZhcyanA3%nUxeJT%*CIQjeizEV z6#3`$;;c`9nYPC{xKrVR-ERU(RoPcx{dUk28QYA@M=oUhdS00NejxY~mZXJDwPmX9 zpQ$#bJ#vkVuEj##yv{dC#k0%ZWT)%{se<8~Z6hA#I zZx|e8@@87|prnTyC^T+jTdEBiTGPL7@Gu>*Zp1L>ixa9WXif}2YD8nX4Jd{Yuz55z zYFO06H=r22_aGFRN2HMEE;k)x?^#+=L=Q<(xjMh+qlTqT=CWDgcahj9W#?F-$vE*Lv!!#~K_ttRPf$1O3EGLIP z{68x5f-pH&)sp*}u1w+7>e%27emq!`Z0xXuE@rBkA9^y?{GT~9{eCsKM*_2(e01oK YD0|I0xqN*1n}E_g@Jv2yJWB500Kv`p8UO$Q delta 6439 zcmeI0UrbY17{EEKm6}m#VS`J-(psk3QhG0=1Vs`GbgoXF1)1VPfL2(dn{oqaG%?aR z_a|-)%qO00N-ZpLO9rLvGH{zwmhixXb6wnGmJsN&Y%vNO#`z*_?A)(KaoK~u>|x%Q z_V?X$&OPUz+xzvqzqfx<-MXX>tx&0xhhJ)2Ev-}~6XOwQ5$|qp+TFObwS{lWZ)mJ* z*(WwO@AowC^6YJeufBP9*>k%q%bIpV{cW?9mAg!>c9lA6*Fwjg&%m8-gQmIdk|=H^ z^kNz@LVW=T5xW7x=`MJ2)(q_*a>NQ1b`Ol2Q{cD1EHL$_9mG?+Kzr3LkMGiv0w_LZ zfJm|n9BYb*6MMV+SHb*`9C2Zk<}(FPDtd%@kG0!?SEkl5{o$S*k%IKV+) zx0i}4B7ocP1yhceCaZ~=hT}dVM5>Q|S(^AwyuE z&zBc>QbUS?|Hw=I8d5_239M(QV;>o3Ju^T!d=S2k7@*{51Bh)-(3NFEiv`zw<0bKRJ2`0}JS6#_ zfx~?^NW9L|kdCaUXSD37yT1x*XLz=q8>vt3c42ZgOkB4?@N?Gq*7NY%wEUgMrvBO@ zfbYhB2oK^B7`5cVdjmY%<&_}J*uWU%+1+~_guwtcvU5udgM|d9rg?VRIkYyN*r5Fy z&u-%u@c%B)EN}P|w2os9!g_fLDfBW&)jmAUb3nau#wHvI*IQY(=&r3&;X;F>*1o z1KEM>M0O&(kX^`|kT)T_k=@8u$W_SI$koU-$Ti6I$o0q#$PLIMvWOf)4j~UA4OhITrs<^}ycJCv8jgL(i3^`oSx|m|DQm$}tDg3Y$+`V*VjI3>^ghE}pc2 zuiMH5ggiPbAed7?`C!NM-xCng_@0Eocu_<|8<)xm<}2l7!#VFVVKJ;E r3AB|;l2ELsY)v0!tNHIqVuUG;a}TLAuD%H=sZ%poMpk5#SM`4bhou81 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 d0287e91ecaf4eaa8a647693c94380d9185a1296..a7d44b55413ad60e422335b85570eae7f8ef57ad 100644 GIT binary patch delta 4178 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 A0{{R3 delta 4113 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 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 2f2cd5cccff43f5abd9e32854ad3bbe7a994c792..82e00652163427427f0e363c96a18d7135e11918 100644 GIT binary patch delta 16 XcmaFH{ET_SJw}eXU*&rI85kG9 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�HG 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 MM)gm}z(M~10Ef;!_W%F@ delta 18919 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 N^pCYMZ;#Q){{zh%XG8!1 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant index 7922055a8251b89b19f98d9aedd460ebc6157b3a..5d8207dfdbe7d0e8951d889bb2ea9d98cee852ad 100644 GIT binary patch delta 16 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 literal 20213 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 From 60a0d2ba01d3e04d090ae2ce8add30b13df2cc36 Mon Sep 17 00:00:00 2001 From: mrieggeramzn <61609885+mrieggeramzn@users.noreply.github.com> Date: Thu, 30 Sep 2021 15:34:12 -0700 Subject: [PATCH 098/115] Atom/mriegger/decalnormalmaps (#4302) * Adding normal maps to decals initial commit Signed-off-by: mrieggeramzn * Adding checks for normal maps not present Signed-off-by: mrieggeramzn * Readding the proper switch statement Signed-off-by: mrieggeramzn * Addressing PR feedback, adding brackets Signed-off-by: mrieggeramzn * Adding comments Signed-off-by: mrieggeramzn * fixing compile issue Signed-off-by: mrieggeramzn --- .../ShaderLib/Atom/Features/PBR/Decals.azsli | 31 ++-- .../ShaderResourceGroups/Decals/ViewSrg.azsli | 18 ++- .../Code/Source/Decals/DecalTextureArray.cpp | 137 ++++++++++++------ .../Code/Source/Decals/DecalTextureArray.h | 37 +++-- .../DecalTextureArrayFeatureProcessor.cpp | 36 ++++- .../DecalTextureArrayFeatureProcessor.h | 3 +- .../Tests/Decals/DecalTextureArrayTests.cpp | 2 +- 7 files changed, 181 insertions(+), 83 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli index 1bd8e0b9a5..5e7088617b 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli @@ -16,6 +16,7 @@ #include #include #include +#include void ApplyDecal(uint currDecalIndex, inout Surface surface); @@ -47,9 +48,10 @@ void ApplyDecal(uint currDecalIndex, inout Surface surface) ViewSrg::Decal decal = ViewSrg::m_decals[currDecalIndex]; float3x3 decalRot = MatrixFromQuaternion(decal.m_quaternion); - + decalRot = transpose(decalRot); + float3 localPos = surface.position - decal.m_position; - localPos = mul(localPos, decalRot); + localPos = mul(decalRot, localPos); float3 decalUVW = localPos * rcp(decal.m_halfSize); if(decalUVW.x >= -1.0f && decalUVW.x <= 1.0f && @@ -63,30 +65,39 @@ void ApplyDecal(uint currDecalIndex, inout Surface surface) decalUVW.y *= -1; float3 decalUV = float3(decalUVW.xy * 0.5f + 0.5f, textureIndex); - + float3 decalSample; float4 baseMap = 0; + float2 normalMap = 0; switch(textureArrayIndex) { case 0: - baseMap = ViewSrg::m_decalTextureArray0.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse0.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps0.Sample(PassSrg::LinearSampler, decalUV); break; case 1: - baseMap = ViewSrg::m_decalTextureArray1.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse1.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps1.Sample(PassSrg::LinearSampler, decalUV); break; case 2: - baseMap = ViewSrg::m_decalTextureArray2.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse2.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps2.Sample(PassSrg::LinearSampler, decalUV); break; case 3: - baseMap = ViewSrg::m_decalTextureArray3.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse3.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps3.Sample(PassSrg::LinearSampler, decalUV); break; case 4: - baseMap = ViewSrg::m_decalTextureArray4.Sample(PassSrg::LinearSampler, decalUV); - break; + baseMap = ViewSrg::m_decalTextureArrayDiffuse4.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps4.Sample(PassSrg::LinearSampler, decalUV); + break; } float opacity = baseMap.a * decal.m_opacity * GetDecalAttenuation(surface.normal, decalRot[2], decal.m_angleAttenuation); - surface.albedo = lerp(surface.albedo, baseMap.rgb, opacity); + surface.albedo = lerp(surface.albedo, baseMap.rgb, opacity); + + float3 normalMapWS = GetWorldSpaceNormal(normalMap, decalRot[2], decalRot[0], decalRot[1], 1.0f); + surface.normal = normalize(lerp(surface.normal, normalMapWS, opacity)); } } diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli index 16b23432e1..260614b0f7 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli @@ -31,12 +31,18 @@ partial ShaderResourceGroup ViewSrg // e.g. m_decalTextureArray0 might store 24 textures @128x128, // m_decalTextureArray1 might store 16 * 256x256 // and m_decalTextureArray2 might store 4 @ 512x512 - - Texture2DArray m_decalTextureArray0; - Texture2DArray m_decalTextureArray1; - Texture2DArray m_decalTextureArray2; - Texture2DArray m_decalTextureArray3; - Texture2DArray m_decalTextureArray4; + // This must match the variable NumTextureArrays in DecalTextureArrayFeatureProcessor.h + Texture2DArray m_decalTextureArrayDiffuse0; + Texture2DArray m_decalTextureArrayDiffuse1; + Texture2DArray m_decalTextureArrayDiffuse2; + Texture2DArray m_decalTextureArrayDiffuse3; + Texture2DArray m_decalTextureArrayDiffuse4; + + Texture2DArray m_decalTextureArrayNormalMaps0; + Texture2DArray m_decalTextureArrayNormalMaps1; + Texture2DArray m_decalTextureArrayNormalMaps2; + Texture2DArray m_decalTextureArrayNormalMaps3; + Texture2DArray m_decalTextureArrayNormalMaps4; uint m_decalCount; } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp index ebdc884ecf..87ac0a9679 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ - #include "DecalTextureArray.h" #include #include @@ -24,7 +23,16 @@ namespace AZ { namespace { - static const char* BaseColorTextureMapName = "baseColor.textureMap"; + static AZ::Name GetMapName(const DecalMapType mapType) + { + // Using local static to avoid cost of creating AZ::Name. Also so that this can be called from other static functions + static AZStd::array mapNames = + { + AZ::Name("baseColor.textureMap"), + AZ::Name("normal.textureMap") + }; + return mapNames[mapType]; + } static AZ::Data::AssetId GetImagePoolId() { @@ -40,6 +48,7 @@ namespace AZ return asset; } + // Extract exactly which texture asset we need to load from the given material and map type (diffuse, normal, etc). static AZ::Data::Asset GetStreamingImageAsset(const AZ::RPI::MaterialAsset& materialAsset, const AZ::Name& propertyName) { if (!materialAsset.IsReady()) @@ -78,11 +87,6 @@ namespace AZ const AZ::RPI::MaterialAsset* materialAsset = materialAssetData.GetAs(); return GetStreamingImageAsset(*materialAsset, propertyName); } - - AZ::Data::Asset GetBaseColorImageAsset(const AZ::Data::Asset materialAssetData) - { - return GetStreamingImageAsset(materialAssetData, AZ::Name(BaseColorTextureMapName)); - } } int DecalTextureArray::FindMaterial(const AZ::Data::AssetId materialAssetId) const @@ -103,7 +107,7 @@ namespace AZ { AZ_Error("DecalTextureArray", FindMaterial(materialAssetId) == -1, "Adding material when it already exists in the array"); // Invalidate the existing texture array, as we need to repack it taking into account the new material. - m_textureArrayPacked = nullptr; + AZStd::fill(m_textureArrayPacked.begin(), m_textureArrayPacked.end(), nullptr); MaterialData materialData; materialData.m_materialAssetId = materialAssetId; @@ -122,42 +126,42 @@ namespace AZ return m_materials[index].m_materialAssetId; } - RHI::Size DecalTextureArray::GetImageDimensions() const + RHI::Size DecalTextureArray::GetImageDimensions(const DecalMapType mapType) const { AZ_Assert(m_materials.size() > 0, "GetImageDimensions() cannot be called until at least one material has been added"); const int iter = m_materials.begin(); // All textures in a texture array must have the same size, so just pick the first const MaterialData& firstMaterial = m_materials[iter]; - const auto& baseColorAsset = GetBaseColorImageAsset(firstMaterial.m_materialAssetData); + const auto& baseColorAsset = GetStreamingImageAsset(firstMaterial.m_materialAssetData, GetMapName(mapType)); return baseColorAsset->GetImageDescriptor().m_size; } - const AZ::Data::Instance& DecalTextureArray::GetPackedTexture() const + const AZ::Data::Instance& DecalTextureArray::GetPackedTexture(const DecalMapType mapType) const { - return m_textureArrayPacked; + return m_textureArrayPacked[mapType]; } bool DecalTextureArray::IsValidDecalMaterial(const AZ::RPI::MaterialAsset& materialAsset) { - return GetStreamingImageAsset(materialAsset, AZ::Name(BaseColorTextureMapName)).IsReady(); + return GetStreamingImageAsset(materialAsset, GetMapName(DecalMapType_Diffuse)).IsReady(); } - AZ::Data::Asset DecalTextureArray::BuildPackedMipChainAsset(const size_t numTexturesToCreate) + AZ::Data::Asset DecalTextureArray::BuildPackedMipChainAsset(const DecalMapType mapType, const size_t numTexturesToCreate) { RPI::ImageMipChainAssetCreator assetCreator; - const uint32_t mipLevels = GetNumMipLevels(); + const uint32_t mipLevels = GetNumMipLevels(mapType); - assetCreator.Begin(Data::AssetId(AZ::Uuid::CreateRandom()), static_cast(mipLevels), aznumeric_cast(numTexturesToCreate)); + assetCreator.Begin(Data::AssetId(AZ::Uuid::CreateRandom()), aznumeric_cast(mipLevels), aznumeric_cast(numTexturesToCreate)); for (uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) { - const auto& layout = GetLayout(mipLevel); + const auto& layout = GetLayout(mapType, mipLevel); assetCreator.BeginMip(layout); for (int i = 0; i < m_materials.array_size(); ++i) { - const auto rawData = GetRawImageData(i, mipLevel); - assetCreator.AddSubImage(rawData.data(), rawData.size()); + const auto imageData = GetRawImageData(GetMapName(mapType), i, mipLevel); + assetCreator.AddSubImage(imageData.data(), imageData.size()); } assetCreator.EndMip(); @@ -169,10 +173,12 @@ namespace AZ return AZStd::move(asset); } - RHI::ImageDescriptor DecalTextureArray::CreatePackedImageDescriptor(const uint16_t arraySize, const uint16_t mipLevels) const + RHI::ImageDescriptor DecalTextureArray::CreatePackedImageDescriptor( + const DecalMapType mapType, const uint16_t arraySize, const uint16_t mipLevels) const { - const RHI::Size imageDimensions = GetImageDimensions(); - RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2DArray(RHI::ImageBindFlags::ShaderRead, imageDimensions.m_width, imageDimensions.m_height, arraySize, GetFormat()); + const RHI::Size imageDimensions = GetImageDimensions(mapType); + RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2DArray( + RHI::ImageBindFlags::ShaderRead, imageDimensions.m_width, imageDimensions.m_height, arraySize, GetFormat(mapType)); imageDescriptor.m_mipLevels = mipLevels; return imageDescriptor; } @@ -189,21 +195,34 @@ namespace AZ } const size_t numTexturesToCreate = m_materials.array_size(); - const auto mipChainAsset = BuildPackedMipChainAsset(numTexturesToCreate); - RHI::ImageViewDescriptor imageViewDescriptor; - imageViewDescriptor.m_isArray = true; + for (int i = 0; i < DecalMapType_Num; ++i) + { + const DecalMapType mapType = aznumeric_cast(i); + if (!AreAllTextureMapsPresent(mapType)) + { + AZ_Warning("DecalTextureArray", true, "Missing decal texture maps for %s. Please make sure all maps of this type are present.\n", GetMapName(mapType).GetCStr()); + m_textureArrayPacked[i] = nullptr; + continue; + } - RPI::StreamingImageAssetCreator assetCreator; - assetCreator.Begin(Data::AssetId(Uuid::CreateRandom())); - assetCreator.SetPoolAssetId(GetImagePoolId()); - assetCreator.SetFlags(RPI::StreamingImageFlags::None); - assetCreator.SetImageDescriptor(CreatePackedImageDescriptor(aznumeric_cast(numTexturesToCreate), GetNumMipLevels())); - assetCreator.SetImageViewDescriptor(imageViewDescriptor); - assetCreator.AddMipChainAsset(*mipChainAsset); - Data::Asset packedAsset; - const bool createdOk = assetCreator.End(packedAsset); - AZ_Error("TextureArrayData", createdOk, "Pack() call failed."); - m_textureArrayPacked = createdOk ? RPI::StreamingImage::FindOrCreate(packedAsset) : nullptr; + const auto mipChainAsset = BuildPackedMipChainAsset(mapType, numTexturesToCreate); + RHI::ImageViewDescriptor imageViewDescriptor; + imageViewDescriptor.m_isArray = true; + + RPI::StreamingImageAssetCreator assetCreator; + assetCreator.Begin(Data::AssetId(Uuid::CreateRandom())); + assetCreator.SetPoolAssetId(GetImagePoolId()); + assetCreator.SetFlags(RPI::StreamingImageFlags::None); + assetCreator.SetImageDescriptor( + CreatePackedImageDescriptor(mapType, aznumeric_cast(numTexturesToCreate), GetNumMipLevels(mapType))); + assetCreator.SetImageViewDescriptor(imageViewDescriptor); + assetCreator.AddMipChainAsset(*mipChainAsset); + Data::Asset packedAsset; + const bool createdOk = assetCreator.End(packedAsset); + AZ_Error("TextureArrayData", createdOk, "Pack() call failed."); + m_textureArrayPacked[i] = createdOk ? RPI::StreamingImage::FindOrCreate(packedAsset) : nullptr; + + } // Free unused memory ClearAssets(); @@ -225,29 +244,30 @@ namespace AZ } } - uint16_t DecalTextureArray::GetNumMipLevels() const + uint16_t DecalTextureArray::GetNumMipLevels(const DecalMapType mapType) const { AZ_Assert(m_materials.size() > 0, "GetNumMipLevels() cannot be called until at least one material has been added"); // All decals in a texture array must have the same number of mips, so just pick the first const int iter = m_materials.begin(); const MaterialData& firstMaterial = m_materials[iter]; - const auto& baseColorAsset = GetBaseColorImageAsset(firstMaterial.m_materialAssetData); - return baseColorAsset->GetImageDescriptor().m_mipLevels; + const auto& imageAsset = GetStreamingImageAsset(firstMaterial.m_materialAssetData, GetMapName(mapType)); + return imageAsset->GetImageDescriptor().m_mipLevels; } - RHI::ImageSubresourceLayout DecalTextureArray::GetLayout(int mip) const + RHI::ImageSubresourceLayout DecalTextureArray::GetLayout(const DecalMapType mapType, int mip) const { AZ_Assert(m_materials.size() > 0, "GetLayout() cannot be called unless at least one material has been added"); const int iter = m_materials.begin(); - const auto& descriptor = GetBaseColorImageAsset(m_materials[iter].m_materialAssetData)->GetImageDescriptor(); + const auto& descriptor = + GetStreamingImageAsset(m_materials[iter].m_materialAssetData, GetMapName(mapType))->GetImageDescriptor(); RHI::Size mipSize = descriptor.m_size; mipSize.m_width >>= mip; mipSize.m_height >>= mip; return AZ::RHI::GetImageSubresourceLayout(mipSize, descriptor.m_format); } - AZStd::array_view DecalTextureArray::GetRawImageData(int arrayLevel, const int mip) const + AZStd::array_view DecalTextureArray::GetRawImageData(const AZ::Name& mapName, int arrayLevel, const int mip) const { // We always want to provide valid data to the AssetCreator for each texture. // If this spot in the array is empty, just provide some random image as filler. @@ -257,17 +277,20 @@ namespace AZ { arrayLevel = m_materials.begin(); } - - const auto image = GetBaseColorImageAsset(m_materials[arrayLevel].m_materialAssetData); + const auto image = GetStreamingImageAsset(m_materials[arrayLevel].m_materialAssetData, mapName); + if (!image) + { + return {}; + } const auto srcData = image->GetSubImageData(mip, 0); return srcData; } - AZ::RHI::Format DecalTextureArray::GetFormat() const + AZ::RHI::Format DecalTextureArray::GetFormat(const DecalMapType mapType) const { AZ_Assert(m_materials.size() > 0, "GetFormat() can only be called after at least one material has been added."); const int iter = m_materials.begin(); - const auto& baseColorAsset = GetBaseColorImageAsset(m_materials[iter].m_materialAssetData); + const auto& baseColorAsset = GetStreamingImageAsset(m_materials[iter].m_materialAssetData, GetMapName(mapType)); return baseColorAsset->GetImageDescriptor().m_format; } @@ -290,6 +313,25 @@ namespace AZ return id.IsValid() && materialData.m_materialAssetData.IsReady(); } + bool DecalTextureArray::AreAllTextureMapsPresent(const DecalMapType mapType) const + { + int iter = m_materials.begin(); + while (iter != -1) + { + if (!IsTextureMapPresentInMaterial(m_materials[iter], mapType)) + { + return false; + } + iter = m_materials.next(iter); + } + return true; + } + + bool DecalTextureArray::IsTextureMapPresentInMaterial(const MaterialData& materialData, const DecalMapType mapType) const + { + return GetStreamingImageAsset(materialData.m_materialAssetData, GetMapName(mapType)).IsReady(); + } + void DecalTextureArray::ClearAssets() { int iter = m_materials.begin(); @@ -330,7 +372,8 @@ namespace AZ if (m_materials.size() == 0) return false; - return m_textureArrayPacked == nullptr; + // We pack all diffuse/normal/etc in one go, so just check to see if the diffusemaps need packing + return m_textureArrayPacked[DecalMapType_Diffuse] == nullptr; } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h index eb0f825e08..97bd8b9cbe 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h @@ -28,8 +28,18 @@ namespace AZ namespace Render { + enum DecalMapType : uint32_t + { + DecalMapType_Diffuse, + DecalMapType_Normal, + DecalMapType_Num + }; + //! Helper class used by DecalTextureArrayFeatureProcessor. //! Given a set of images (all with the same dimensions and format), it can pack them together into a single textureArray that can be sent to the GPU. + //! Note that once textures are packed, this class will release any material references + //! This might free memory if nothing else is holding onto them + //! The class DOES keep note of which material asset ids were added, so it can load them again if necessary if the whole thing needs to be repacked class DecalTextureArray : public Data::AssetBus::MultiHandler { public: @@ -40,8 +50,12 @@ namespace AZ AZ::Data::AssetId GetMaterialAssetId(const int index) const; + // Packs all the added materials into one texture array per DecalMapType. void Pack(); - const Data::Instance& GetPackedTexture() const; + + // Note that we pack each type into a separate texture array. This is because formats are + // often different (BC5 for normals, BC7 for diffuse, etc) + const Data::Instance& GetPackedTexture(const DecalMapType mapType) const; static bool IsValidDecalMaterial(const RPI::MaterialAsset& materialAsset); @@ -56,22 +70,25 @@ namespace AZ void OnAssetReady(Data::Asset asset) override; + // Returns the index of the material in the m_materials container. -1 if not present. int FindMaterial(const AZ::Data::AssetId materialAssetId) const; // packs the contents of the source images into a texture array readable by the GPU and returns it - AZ::Data::Asset BuildPackedMipChainAsset(const size_t numTexturesToCreate); + AZ::Data::Asset BuildPackedMipChainAsset(const DecalMapType mapType, const size_t numTexturesToCreate); + RHI::ImageDescriptor CreatePackedImageDescriptor(const DecalMapType mapType, const uint16_t arraySize, const uint16_t mipLevels) const; - RHI::ImageDescriptor CreatePackedImageDescriptor(const uint16_t arraySize, const uint16_t mipLevels) const; - - uint16_t GetNumMipLevels() const; - RHI::Size GetImageDimensions() const; - RHI::Format GetFormat() const; - RHI::ImageSubresourceLayout GetLayout(int mip) const; - AZStd::array_view GetRawImageData(int arrayLevel, int mip) const; + uint16_t GetNumMipLevels(const DecalMapType mapType) const; + RHI::Size GetImageDimensions(const DecalMapType mapType) const; + RHI::Format GetFormat(const DecalMapType mapType) const; + RHI::ImageSubresourceLayout GetLayout(const DecalMapType mapType, int mip) const; + AZStd::array_view GetRawImageData(const AZ::Name& mapName, int arrayLevel, int mip) const; bool AreAllAssetsReady() const; bool IsAssetReady(const MaterialData& materialData) const; + bool AreAllTextureMapsPresent(const DecalMapType mapType) const; + bool IsTextureMapPresentInMaterial(const MaterialData& materialData, const DecalMapType mapType) const; + void ClearAssets(); void ClearAsset(MaterialData& materialData); @@ -81,7 +98,7 @@ namespace AZ bool NeedsPacking() const; IndexableList m_materials; - Data::Instance m_textureArrayPacked; + AZStd::array, DecalMapType_Num> m_textureArrayPacked; AZStd::unordered_set m_assetsCurrentlyLoading; }; diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp index c0b8f3315a..e5bf0bd9fa 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp @@ -322,13 +322,30 @@ namespace AZ void DecalTextureArrayFeatureProcessor::CacheShaderIndices() { - for (int i = 0; i < NumTextureArrays; ++i) - { - const RHI::ShaderResourceGroupLayout* viewSrgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get(); - const AZStd::string baseName = "m_decalTextureArray" + AZStd::to_string(i); + // The azsl shader should define several texture arrays such as: + // Texture2DArray m_decalTextureArrayDiffuse0; + // Texture2DArray m_decalTextureArrayDiffuse1; + // Texture2DArray m_decalTextureArrayDiffuse2; + // and + // Texture2DArray m_decalTextureArrayNormalMaps0; + // Texture2DArray m_decalTextureArrayNormalMaps1; + // Texture2DArray m_decalTextureArrayNormalMaps2; + static const AZStd::array ShaderNames = { "m_decalTextureArrayDiffuse", + "m_decalTextureArrayNormalMaps" }; - m_decalTextureArrayIndices[i] = viewSrgLayout->FindShaderInputImageIndex(Name(baseName.c_str())); - AZ_Warning("DecalTextureArrayFeatureProcessor", m_decalTextureArrayIndices[i].IsValid(), "Unable to find %s in decal shader.", baseName.c_str()); + for (int mapType = 0; mapType < DecalMapType_Num; ++mapType) + { + for (int texArrayIdx = 0; texArrayIdx < NumTextureArrays; ++texArrayIdx) + { + const RHI::ShaderResourceGroupLayout* viewSrgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get(); + const AZStd::string baseName = ShaderNames[mapType] + AZStd::to_string(texArrayIdx); + + m_decalTextureArrayIndices[texArrayIdx][mapType] = viewSrgLayout->FindShaderInputImageIndex(Name(baseName.c_str())); + AZ_Warning( + "DecalTextureArrayFeatureProcessor", m_decalTextureArrayIndices[texArrayIdx][mapType].IsValid(), + "Unable to find %s in decal shader.", + baseName.c_str()); + } } } @@ -411,8 +428,11 @@ namespace AZ int iter = m_textureArrayList.begin(); while (iter != -1) { - const auto& packedTexture = m_textureArrayList[iter].second.GetPackedTexture(); - view->GetShaderResourceGroup()->SetImage(m_decalTextureArrayIndices[iter], packedTexture); + for (int mapType = 0 ; mapType < DecalMapType_Num ; ++mapType) + { + const auto& packedTexture = m_textureArrayList[iter].second.GetPackedTexture(aznumeric_cast(mapType)); + view->GetShaderResourceGroup()->SetImage(m_decalTextureArrayIndices[iter][mapType], packedTexture); + } iter = m_textureArrayList.next(iter); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h index 57c5c69e0d..13a6682629 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h @@ -89,6 +89,7 @@ namespace AZ private: // Number of size and format permutations + // This number should match the number of texture arrays in Decals/ViewSrg.azsli static constexpr int NumTextureArrays = 5; static constexpr const char* FeatureProcessorName = "DecalTextureArrayFeatureProcessor"; @@ -128,7 +129,7 @@ namespace AZ // 4 textures @ 512x512 IndexableList < AZStd::pair < AZ::RHI::Size, DecalTextureArray>> m_textureArrayList; - AZStd::array m_decalTextureArrayIndices; + AZStd::array, NumTextureArrays> m_decalTextureArrayIndices; GpuBufferHandler m_decalBufferHandler; AsyncLoadTracker m_materialLoadTracker; diff --git a/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp b/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp index fcbcec0256..84c2b88507 100644 --- a/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp +++ b/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp @@ -42,7 +42,7 @@ namespace UnitTest { AZ::Render::DecalTextureArray decalTextureArray; decalTextureArray.Pack(); - auto nothing = decalTextureArray.GetPackedTexture(); + auto nothing = decalTextureArray.GetPackedTexture(AZ::Render::DecalMapType_Diffuse); EXPECT_EQ(nothing, nullptr); } From e1c49e436dab7e8ee58bd4da885736b426e201aa Mon Sep 17 00:00:00 2001 From: "rgba16f [Amazon]" <82187279+rgba16f@users.noreply.github.com> Date: Thu, 30 Sep 2021 17:45:33 -0500 Subject: [PATCH 099/115] convert atom to task graph (#4230) * Intial attempt to convert the Atom/RHI/FrameScheduler to use the new TaskGraph api Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Avoid enqueuing work on the active task thread if the submitted task graph is waitable When submitting a task graph, supplying a wait event implies that dependent jobs must occur on threads that do not wait on the event (in the absence of work stealing). This change prevents this by adding a notion of a task thread enable/disable state, and prohibiting dependent jobs from being enqueued on waiting threads. Signed-off-by: Jeremy Ong * Convert RPI/Scene to use TaskGraph pass 1, Culling jobs remain on the old system Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * RemoveTask Graph changes from the FrameScheduler::ExecuteGroups, use old job system instead Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Per review, removing commented out code Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Cleanup debug code, & build fix Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Add a cvar & interface to query whether to use jobs or task graph Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Make TaskGraph assert if you try to wait inside a job Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Fix TaskTest SpawnSubgraph to account for the new TaskGraphEvent assert on wait in a running task Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * 3 minor cleanups. 1) Events always store a ptr to their executor 2) Fix clang compile error 3) remove an early out. Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Fix double group end that was causing assert/crash plus misc minor diff's with development Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Fix deallocation failure on deactivation of the TaskGraphSystemComponent. Also make the system component account for multiple creation in Unit Tests. Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Update with PR feedback 1) Rename UseTaskGraph to IsTaskGraphActive & update related code 2) prefer TaskExecutor::SetInstance 3) add comments and remove commented out code Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Fix incorrect RTTI name for TaskGraphActiveInterface Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Move TaskGraphSystemComponent CRC calculation to a shared variable Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> Co-authored-by: Jeremy Ong --- Code/Framework/AzCore/AzCore/AzCoreModule.cpp | 3 + .../AzCore/AzCore/Task/TaskExecutor.cpp | 85 ++++-- .../AzCore/AzCore/Task/TaskExecutor.h | 7 +- .../AzCore/AzCore/Task/TaskGraph.cpp | 8 +- Code/Framework/AzCore/AzCore/Task/TaskGraph.h | 15 + .../AzCore/AzCore/Task/TaskGraph.inl | 10 +- .../AzCore/Task/TaskGraphSystemComponent.cpp | 88 ++++++ .../AzCore/Task/TaskGraphSystemComponent.h | 47 +++ .../AzCore/AzCore/azcore_files.cmake | 2 + Code/Framework/AzCore/Tests/TaskTests.cpp | 84 +++++- .../AzFramework/Application/Application.cpp | 2 + .../Code/Include/Atom/RHI/FrameScheduler.h | 3 + .../RHI/Code/Source/RHI/FrameScheduler.cpp | 119 ++++++-- .../Code/Source/RHI/AsyncUploadQueue.cpp | 1 + .../RPI/Code/Include/Atom/RPI.Public/Scene.h | 19 ++ .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 281 ++++++++++++++---- .../001_DefaultWhite.material | 4 +- .../002_BaseColorLerp.material | 4 +- 18 files changed, 652 insertions(+), 130 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp create mode 100644 Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h diff --git a/Code/Framework/AzCore/AzCore/AzCoreModule.cpp b/Code/Framework/AzCore/AzCore/AzCoreModule.cpp index c60ea1bd72..ec45335f95 100644 --- a/Code/Framework/AzCore/AzCore/AzCoreModule.cpp +++ b/Code/Framework/AzCore/AzCore/AzCoreModule.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace AZ { @@ -41,6 +42,7 @@ namespace AZ TimeSystemComponent::CreateDescriptor(), LoggerSystemComponent::CreateDescriptor(), EventSchedulerSystemComponent::CreateDescriptor(), + TaskGraphSystemComponent::CreateDescriptor(), #if !defined(AZCORE_EXCLUDE_LUA) ScriptSystemComponent::CreateDescriptor(), @@ -55,6 +57,7 @@ namespace AZ azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), + azrtti_typeid(), }; } } diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp index 2bb88fbfa2..d2d19d1359 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp @@ -190,11 +190,13 @@ namespace AZ class TaskWorker { public: - void Spawn(::AZ::TaskExecutor& executor, size_t id, AZStd::semaphore& initSemaphore, bool affinitize) + static thread_local TaskWorker* t_worker; + + void Spawn(::AZ::TaskExecutor& executor, uint32_t id, AZStd::semaphore& initSemaphore, bool affinitize) { m_executor = &executor; - AZStd::string threadName = AZStd::string::format("TaskWorker %zu", id); + AZStd::string threadName = AZStd::string::format("TaskWorker %u", id); AZStd::thread_desc desc = {}; desc.m_name = threadName.c_str(); if (affinitize) @@ -205,12 +207,29 @@ namespace AZ m_thread = AZStd::thread{ [this, &initSemaphore] { + t_worker = this; initSemaphore.release(); Run(); }, &desc }; } + // Threads that wait on a graph to complete are disqualified from receiving tasks until the wait finishes + void Disable() + { + m_enabled = false; + } + + void Enable() + { + m_enabled = true; + } + + bool Enabled() const + { + return m_enabled; + } + void Join() { m_active.store(false, AZStd::memory_order_release); @@ -222,11 +241,7 @@ namespace AZ { m_queue.Enqueue(task); - if (!m_busy.exchange(true)) - { - // The worker was idle prior to enqueueing the task, release the semaphore - m_semaphore.release(); - } + m_semaphore.release(); } private: @@ -234,7 +249,6 @@ namespace AZ { while (m_active) { - m_busy = false; m_semaphore.acquire(); if (!m_active) @@ -242,8 +256,6 @@ namespace AZ return; } - m_busy = true; - Task* task = m_queue.TryDequeue(); while (task) { @@ -271,12 +283,15 @@ namespace AZ AZStd::thread m_thread; AZStd::atomic m_active; - AZStd::atomic m_busy; + AZStd::atomic m_enabled = true; AZStd::binary_semaphore m_semaphore; ::AZ::TaskExecutor* m_executor; TaskQueue m_queue; + friend class ::AZ::TaskExecutor; }; + + thread_local TaskWorker* TaskWorker::t_worker = nullptr; } // namespace Internal static EnvironmentVariable s_executor; @@ -291,13 +306,16 @@ namespace AZ return **s_executor; } - // TODO: Create the default executor as part of a component (as in TaskManagerComponent) void TaskExecutor::SetInstance(TaskExecutor* executor) { - AZ_Assert(!s_executor, "Attempting to set the global task executor more than once"); - - s_executor = AZ::Environment::CreateVariable("GlobalTaskExecutor"); - s_executor.Set(executor); + if (!executor) + { + s_executor.Reset(); + } + else if (!s_executor) // ignore any calls to set after the first (this happens in unit tests that create new system entities) + { + s_executor = AZ::Environment::CreateVariable(s_executorName, executor); + } } TaskExecutor::TaskExecutor(uint32_t threadCount) @@ -307,14 +325,12 @@ namespace AZ m_workers = reinterpret_cast(azmalloc(m_threadCount * sizeof(Internal::TaskWorker))); - bool affinitize = m_threadCount == AZStd::thread::hardware_concurrency(); - AZStd::semaphore initSemaphore; - for (size_t i = 0; i != m_threadCount; ++i) + for (uint32_t i = 0; i != m_threadCount; ++i) { new (m_workers + i) Internal::TaskWorker{}; - m_workers[i].Spawn(*this, i, initSemaphore, affinitize); + m_workers[i].Spawn(*this, i, initSemaphore, false); } for (size_t i = 0; i != m_threadCount; ++i) @@ -334,9 +350,21 @@ namespace AZ azfree(m_workers); } - void TaskExecutor::Submit(Internal::CompiledTaskGraph& graph) + Internal::TaskWorker* TaskExecutor::GetTaskWorker() + { + if (Internal::TaskWorker::t_worker && Internal::TaskWorker::t_worker->m_executor == this) + { + return Internal::TaskWorker::t_worker; + } + return nullptr; + } + + void TaskExecutor::Submit(Internal::CompiledTaskGraph& graph, TaskGraphEvent* event) { ++m_graphsRemaining; + + event->m_executor = this; // Used to validate event is not waited for inside a job + // Submit all tasks that have no inbound edges for (Internal::Task& task : graph.Tasks()) { @@ -352,11 +380,24 @@ namespace AZ // TODO: Something more sophisticated is likely needed here. // First, we are completely ignoring affinity. // Second, some heuristics on core availability will help distribute work more effectively - m_workers[++m_lastSubmission % m_threadCount].Enqueue(&task); + uint32_t nextWorker = ++m_lastSubmission % m_threadCount; + while (!m_workers[nextWorker].Enabled()) + { + // Graphs that are waiting for the completion of a task graph cannot enqueue tasks onto + // the thread issuing the wait. + nextWorker = ++m_lastSubmission % m_threadCount; + } + + m_workers[nextWorker].Enqueue(&task); } void TaskExecutor::ReleaseGraph() { --m_graphsRemaining; } + + void TaskExecutor::ReactivateTaskWorker() + { + GetTaskWorker()->Enable(); + } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h index dc2fa5a4c8..7e1ff80902 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h @@ -72,14 +72,19 @@ namespace AZ explicit TaskExecutor(uint32_t threadCount = 0); ~TaskExecutor(); - void Submit(Internal::CompiledTaskGraph& graph); + // Submit a task graph for execution. Waitable task graphs cannot enqueue work on the task thread + // that is currently active + void Submit(Internal::CompiledTaskGraph& graph, TaskGraphEvent* event); void Submit(Internal::Task& task); private: friend class Internal::TaskWorker; + friend class TaskGraphEvent; + Internal::TaskWorker* GetTaskWorker(); void ReleaseGraph(); + void ReactivateTaskWorker(); Internal::TaskWorker* m_workers; uint32_t m_threadCount = 0; diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp index 3fb93903c9..f57b06890a 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp @@ -14,6 +14,12 @@ namespace AZ { using Internal::CompiledTaskGraph; + void TaskGraphEvent::Wait() + { + AZ_Assert(m_executor->GetTaskWorker() == nullptr, "Waiting in a task is unsupported"); + m_semaphore.acquire(); + } + void TaskToken::PrecedesInternal(TaskToken& comesAfter) { AZ_Assert(!m_parent.m_submitted, "Cannot mutate a TaskGraph that was previously submitted."); @@ -71,7 +77,7 @@ namespace AZ m_compiledTaskGraph->m_tasks[i].Init(); } - executor.Submit(*m_compiledTaskGraph); + executor.Submit(*m_compiledTaskGraph, waitEvent); if (m_retained) { diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h index 4b454c63de..9553013a4b 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h @@ -22,10 +22,19 @@ namespace AZ namespace Internal { class CompiledTaskGraph; + class TaskWorker; } class TaskExecutor; class TaskGraph; + class TaskGraphActiveInterface + { + public: + AZ_RTTI(TaskGraphActiveInterface, "{08118074-B139-4EF9-B8FD-29F1D6DC9233}"); + + virtual bool IsTaskGraphActive() const = 0; + }; + // A TaskToken is returned each time a Task is added to the TaskGraph. TaskTokens are used to // express dependencies between tasks within the graph, and have no purpose after the graph // is submitted (simply let them go out of scope) @@ -70,9 +79,12 @@ namespace AZ private: friend class ::AZ::Internal::CompiledTaskGraph; friend class TaskGraph; + friend class TaskExecutor; + void Signal(); AZStd::binary_semaphore m_semaphore; + TaskExecutor* m_executor = nullptr; }; // The TaskGraph encapsulates a set of tasks and their interdependencies. After adding @@ -89,6 +101,9 @@ namespace AZ // Reset the state of the task graph to begin recording tasks and edges again // NOTE: Graph must be in a "settled" state (cannot be in-flight) void Reset(); + + // Returns false if 1 or more tasks have been added to the graph + bool IsEmpty(); // Add a task to the graph, retrieiving a token that can be used to express dependencies // between tasks. The first argument specifies the TaskKind, used for tracking the task. diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl index e0ac74ba9d..7b2f0cefdc 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl @@ -33,11 +33,6 @@ namespace AZ return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 }); } - inline void TaskGraphEvent::Wait() - { - m_semaphore.acquire(); - } - inline void TaskGraphEvent::Signal() { m_semaphore.release(); @@ -59,6 +54,11 @@ namespace AZ return { AddTask(descriptor, AZStd::forward(lambdas))... }; } + inline bool TaskGraph::IsEmpty() + { + return m_tasks.empty(); + } + inline void TaskGraph::Detach() { m_retained = false; diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp new file mode 100644 index 0000000000..eed461ecb4 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp @@ -0,0 +1,88 @@ +/* + * 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 + +// Create a cvar as a central location for experimentation with switching from the Job system to TaskGraph system. +AZ_CVAR(bool, cl_activateTaskGraph, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Flag clients of TaskGraph to switch between jobs/taskgraph (Note does not disable task graph system)"); +static constexpr uint32_t TaskExecutorServiceCrc = AZ_CRC_CE("TaskExecutorService"); + +namespace AZ +{ + void TaskGraphSystemComponent::Activate() + { + AZ_Assert(m_taskExecutor == nullptr, "Error multiple activation of the TaskGraphSystemComponent"); + + if (Interface::Get() == nullptr) + { + Interface::Register(this); + m_taskExecutor = aznew TaskExecutor(); + TaskExecutor::SetInstance(m_taskExecutor); + } + } + + void TaskGraphSystemComponent::Deactivate() + { + if (&TaskExecutor::Instance() == m_taskExecutor) // check that our instance is the global instance (not always true in unit tests) + { + m_taskExecutor->SetInstance(nullptr); + } + if (m_taskExecutor) + { + azdestroy(m_taskExecutor); + m_taskExecutor = nullptr; + } + if (Interface::Get() == this) + { + Interface::Unregister(this); + } + } + + void TaskGraphSystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(TaskExecutorServiceCrc); + } + + void TaskGraphSystemComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(TaskExecutorServiceCrc); + } + + void TaskGraphSystemComponent::GetDependentServices([[maybe_unused]] ComponentDescriptor::DependencyArrayType& dependent) + { + } + + void TaskGraphSystemComponent::Reflect(ReflectContext* context) + { + if (SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ; + + if (AZ::EditContext* ec = serializeContext->GetEditContext()) + { + ec->Class + ("TaskGraph", "System component to create the default executor") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Category, "Engine") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) + ; + } + } + } + + bool TaskGraphSystemComponent::IsTaskGraphActive() const + { + return cl_activateTaskGraph; + } +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h new file mode 100644 index 0000000000..a4c6da9539 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h @@ -0,0 +1,47 @@ +/* + * 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 + +namespace AZ +{ + class TaskGraphSystemComponent + : public Component + , public TaskGraphActiveInterface + { + public: + AZ_COMPONENT(AZ::TaskGraphSystemComponent, "{5D56B829-1FEB-43D5-A0BD-E33C0497EFE2}") + + TaskGraphSystemComponent() = default; + + // Implement TaskGraphActiveInterface + bool IsTaskGraphActive() const override; + + private: + ////////////////////////////////////////////////////////////////////////// + // Component base + void Activate() override; + void Deactivate() override; + ////////////////////////////////////////////////////////////////////////// + + /// \ref ComponentDescriptor::GetProvidedServices + static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided); + /// \ref ComponentDescriptor::GetIncompatibleServices + static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible); + /// \ref ComponentDescriptor::GetDependentServices + static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent); + /// \red ComponentDescriptor::Reflect + static void Reflect(ReflectContext* reflection); + + AZ::TaskExecutor* m_taskExecutor = nullptr; + }; +} diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index aa07959997..14579cbf33 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -633,6 +633,8 @@ set(FILES Task/TaskGraph.cpp Task/TaskGraph.h Task/TaskGraph.inl + Task/TaskGraphSystemComponent.h + Task/TaskGraphSystemComponent.cpp Threading/ThreadSafeDeque.h Threading/ThreadSafeDeque.inl Threading/ThreadSafeObject.h diff --git a/Code/Framework/AzCore/Tests/TaskTests.cpp b/Code/Framework/AzCore/Tests/TaskTests.cpp index e743ab6643..9e839f60ee 100644 --- a/Code/Framework/AzCore/Tests/TaskTests.cpp +++ b/Code/Framework/AzCore/Tests/TaskTests.cpp @@ -34,7 +34,7 @@ namespace UnitTest AZ::AllocatorInstance::Create(); AZ::AllocatorInstance::Create(); - m_executor = aznew TaskExecutor(4); + m_executor = aznew TaskExecutor(); } void TearDown() override @@ -236,6 +236,82 @@ namespace UnitTest EXPECT_EQ(x, 1); } + TEST_F(TaskGraphTestFixture, SingleTask) + { + AZStd::atomic_int32_t x = 0; + + TaskGraph graph; + graph.AddTask( + defaultTD, + [&x] + { + x = 1; + }); + + TaskGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(1, x); + } + + + TEST_F(TaskGraphTestFixture, SingleTaskChain) + { + AZStd::atomic_int32_t x = 0; + + TaskGraph graph; + auto a = graph.AddTask( + defaultTD, + [&x] + { + x += 1; + }); + auto b = graph.AddTask( + defaultTD, + [&x] + { + x += 1; + }); + b.Precedes(a); + + TaskGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(2, x); + } + + TEST_F(TaskGraphTestFixture, MultipleIndependentTaskChains) + { + AZStd::atomic_int32_t x = 0; + constexpr int numChains = 5; + + TaskGraph graph; + for( int i = 0; i < numChains; ++i) + { + auto a = graph.AddTask( + defaultTD, + [&x] + { + x += 1; + }); + auto b = graph.AddTask( + defaultTD, + [&x] + { + x += 1; + }); + b.Precedes(a); + } + + TaskGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(2*numChains, x); + } + TEST_F(TaskGraphTestFixture, VariadicInterface) { int x = 0; @@ -388,6 +464,7 @@ namespace UnitTest EXPECT_EQ(3, x); } + // Waiting inside a task is disallowed , test that it fails correctly TEST_F(TaskGraphTestFixture, SpawnSubgraph) { AZStd::atomic x = 0; @@ -434,7 +511,10 @@ namespace UnitTest f.Precedes(g); TaskGraphEvent ev; subgraph.SubmitOnExecutor(*m_executor, &ev); + // TaskGraphEvent::Wait asserts if called on a worker thread, suppress & validate assert + AZ_TEST_START_TRACE_SUPPRESSION; ev.Wait(); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); }); auto d = graph.AddTask( defaultTD, @@ -464,8 +544,6 @@ namespace UnitTest TaskGraphEvent ev; graph.SubmitOnExecutor(*m_executor, &ev); ev.Wait(); - - EXPECT_EQ(3 | 0b100000, x); } TEST_F(TaskGraphTestFixture, RetainedGraph) diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index 12974d03cf..5c7398a95c 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -295,6 +296,7 @@ namespace AzFramework azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), + azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h index ddcee53e69..48e7e0f339 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h @@ -23,6 +23,7 @@ namespace AZ { class Job; + class TaskGraphActiveInterface; namespace RHI { @@ -228,6 +229,8 @@ namespace AZ // list of RayTracingShaderTables that should be built this frame AZStd::vector> m_rayTracingShaderTablesToBuild; + + AZ::TaskGraphActiveInterface* m_taskGraphActive = nullptr; }; } } diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp index 5d2feb1e34..3363675d0e 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp @@ -25,9 +25,11 @@ #include #include +#include #include #include #include +#include namespace AZ { @@ -77,6 +79,8 @@ namespace AZ m_rootScope = m_rootScopeProducer->GetScope(); m_device = &device; + m_taskGraphActive = AZ::Interface::Get(); + m_lastFrameEndTime = AZStd::GetTimeNowTicks(); return ResultCode::Success; @@ -85,6 +89,7 @@ namespace AZ void FrameScheduler::Shutdown() { m_device = nullptr; + m_taskGraphActive = nullptr; m_rootScopeProducer = nullptr; m_rootScope = nullptr; m_frameGraphExecuter = nullptr; @@ -258,50 +263,98 @@ namespace AZ if (m_compileRequest.m_jobPolicy == JobPolicy::Parallel) { - const auto compileGroupsBeginFunction = [](ShaderResourceGroupPool* srgPool) - { - srgPool->CompileGroupsBegin(); - }; - - resourcePoolDatabase.ForEachShaderResourceGroupPool(compileGroupsBeginFunction); - // Iterate over each SRG pool and fork jobs to compile SRGs. const uint32_t compilesPerJob = m_compileRequest.m_shaderResourceGroupCompilesPerJob; - AZ::JobCompletion jobCompletion; - - const auto compileIntervalsFunction = [compilesPerJob, &jobCompletion](ShaderResourceGroupPool* srgPool) + if (m_taskGraphActive && m_taskGraphActive->IsTaskGraphActive()) { - const uint32_t compilesInPool = srgPool->GetGroupsToCompileCount(); - const uint32_t jobCount = DivideByMultiple(compilesInPool, compilesPerJob); + AZ::TaskGraph taskGraph; - for (uint32_t i = 0; i < jobCount; ++i) + const auto compileIntervalsFunction = [compilesPerJob, &taskGraph](ShaderResourceGroupPool* srgPool) { - Interval interval; - interval.m_min = i * compilesPerJob; - interval.m_max = AZStd::min(interval.m_min + compilesPerJob, compilesInPool); + srgPool->CompileGroupsBegin(); + const uint32_t compilesInPool = srgPool->GetGroupsToCompileCount(); + const uint32_t jobCount = DivideByMultiple(compilesInPool, compilesPerJob); + AZ::TaskDescriptor srgCompileDesc{"SrgCompile", "Graphics"}; + AZ::TaskDescriptor srgCompileEndDesc{"SrgCompileEnd", "Graphics"}; - const auto compileGroupsForIntervalLambda = [srgPool, interval]() + auto srgCompileEndTask = taskGraph.AddTask( + srgCompileEndDesc, + [srgPool]() + { + srgPool->CompileGroupsEnd(); + }); + + for (uint32_t i = 0; i < jobCount; ++i) { - AZ_PROFILE_SCOPE(RHI, "FrameScheduler : compileGroupsForIntervalLambda"); - srgPool->CompileGroupsForInterval(interval); - }; + Interval interval; + interval.m_min = i * compilesPerJob; + interval.m_max = AZStd::min(interval.m_min + compilesPerJob, compilesInPool); - AZ::Job* executeGroupJob = AZ::CreateJobFunction(AZStd::move(compileGroupsForIntervalLambda), true, nullptr); - executeGroupJob->SetDependent(&jobCompletion); - executeGroupJob->Start(); + auto compileTask = taskGraph.AddTask( + srgCompileDesc, + [srgPool, interval]() + { + AZ_PROFILE_SCOPE(RHI, "FrameScheduler : compileGroupsForIntervalLambda"); + srgPool->CompileGroupsForInterval(interval); + }); + compileTask.Precedes(srgCompileEndTask); + } + }; + + resourcePoolDatabase.ForEachShaderResourceGroupPool(AZStd::move(compileIntervalsFunction)); + if (!taskGraph.IsEmpty()) + { + AZ::TaskGraphEvent finishedEvent; + taskGraph.Submit(&finishedEvent); + finishedEvent.Wait(); } - }; - - resourcePoolDatabase.ForEachShaderResourceGroupPool(AZStd::move(compileIntervalsFunction)); - - jobCompletion.StartAndWaitForCompletion(); - - const auto compileGroupsEndFunction = [](ShaderResourceGroupPool* srgPool) + } + else // use Job system { - srgPool->CompileGroupsEnd(); - }; + const auto compileGroupsBeginFunction = [](ShaderResourceGroupPool* srgPool) + { + srgPool->CompileGroupsBegin(); + }; - resourcePoolDatabase.ForEachShaderResourceGroupPool(compileGroupsEndFunction); + resourcePoolDatabase.ForEachShaderResourceGroupPool(compileGroupsBeginFunction); + + // Iterate over each SRG pool and fork jobs to compile SRGs. + AZ::JobCompletion jobCompletion; + + const auto compileIntervalsFunction = [compilesPerJob, &jobCompletion](ShaderResourceGroupPool* srgPool) + { + const uint32_t compilesInPool = srgPool->GetGroupsToCompileCount(); + const uint32_t jobCount = DivideByMultiple(compilesInPool, compilesPerJob); + + for (uint32_t i = 0; i < jobCount; ++i) + { + Interval interval; + interval.m_min = i * compilesPerJob; + interval.m_max = AZStd::min(interval.m_min + compilesPerJob, compilesInPool); + + const auto compileGroupsForIntervalLambda = [srgPool, interval]() + { + AZ_PROFILE_SCOPE(RHI, "FrameScheduler : compileGroupsForIntervalLambda"); + srgPool->CompileGroupsForInterval(interval); + }; + + AZ::Job* executeGroupJob = AZ::CreateJobFunction(AZStd::move(compileGroupsForIntervalLambda), true, nullptr); + executeGroupJob->SetDependent(&jobCompletion); + executeGroupJob->Start(); + } + }; + + resourcePoolDatabase.ForEachShaderResourceGroupPool(AZStd::move(compileIntervalsFunction)); + + jobCompletion.StartAndWaitForCompletion(); + + const auto compileGroupsEndFunction = [](ShaderResourceGroupPool* srgPool) + { + srgPool->CompileGroupsEnd(); + }; + + resourcePoolDatabase.ForEachShaderResourceGroupPool(compileGroupsEndFunction); + } } else { diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp index bd163f1419..eadd571452 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp @@ -33,6 +33,7 @@ namespace AZ // Use separate work submission queue from the hw copy queue to avoid the per frame sync. m_copyQueue = CommandQueue::Create(); + m_copyQueue->SetName(AZ::Name("AsyncUpload Queue")); RHI::CommandQueueDescriptor commandQueueDescriptor; commandQueueDescriptor.m_hardwareQueueClass = RHI::HardwareQueueClass::Copy; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h index b1c6aac92d..fc81368331 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -194,6 +195,9 @@ namespace AZ // This function is called every time scene's render pipelines change. void RebuildPipelineStatesLookup(); + // Helper function to wait for end of TaskGraph + void WaitTGEvent(AZ::TaskGraphEvent& completionTGEvent, AZStd::atomic_bool* workToWaitOn = nullptr); + // Helper function for wait and clean up a completion job void WaitAndCleanCompletionJob(AZ::JobCompletion*& completionJob); @@ -204,12 +208,26 @@ namespace AZ // This happens in UpdateSrgs() void PrepareSceneSrg(); + // Implementation functions that allow scene to switch between using Jobs or TaskGraphs + void SimulateTaskGraph(); + void SimulateJobs(); + + void CollectDrawPacketsTaskGraph(); + void CollectDrawPacketsJobs(); + + void FinalizeDrawListsTaskGraph(); + void FinalizeDrawListsJobs(); + // List of feature processors that are active for this scene AZStd::vector m_featureProcessors; // List of pipelines of this scene. Each pipeline has an unique pipeline Id. AZStd::vector m_pipelines; + // CPU simulation TaskGraphEvent to wait for completion of all the simulation tasks + AZ::TaskGraphEvent m_simulationFinishedTGEvent; + AZStd::atomic_bool m_simulationFinishedWorkActive = false; + // CPU simulation job completion for track all feature processors' simulation jobs AZ::JobCompletion* m_simulationCompletion = nullptr; @@ -228,6 +246,7 @@ namespace AZ SceneId m_id; bool m_activated = false; + bool m_taskGraphActive = false; // update during tick, to ensure it only changes on frame boundaries RenderPipelinePtr m_defaultPipeline; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 646cba1999..c5d82c6f29 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include namespace AZ @@ -92,7 +94,14 @@ namespace AZ Scene::~Scene() { - WaitAndCleanCompletionJob(m_simulationCompletion); + if (m_taskGraphActive) + { + WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive); + } + else + { + WaitAndCleanCompletionJob(m_simulationCompletion); + } SceneRequestBus::Handler::BusDisconnect(); // Remove all the render pipelines. Need to process queued changes with pass system before and after remove render pipelines @@ -346,6 +355,47 @@ namespace AZ return nullptr; } + void Scene::SimulateTaskGraph() + { + static const AZ::TaskDescriptor simulationTGDesc{"RPI::Scene::Simulate", "Graphics"}; + AZ::TaskGraph simulationTG; + + for (FeatureProcessorPtr& fp : m_featureProcessors) + { + FeatureProcessor* featureProcessor = fp.get(); + simulationTG.AddTask( + simulationTGDesc, + [this, featureProcessor]() + { + featureProcessor->Simulate(m_simulatePacket); + }); + } + simulationTG.Detach(); + m_simulationFinishedWorkActive = true; + simulationTG.Submit(&m_simulationFinishedTGEvent); + } + + void Scene::SimulateJobs() + { + // Create a new job to track completion. + m_simulationCompletion = aznew AZ::JobCompletion(); + + for (FeatureProcessorPtr& fp : m_featureProcessors) + { + FeatureProcessor* featureProcessor = fp.get(); + const auto jobLambda = [this, featureProcessor]() + { + + featureProcessor->Simulate(m_simulatePacket); + }; + + AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes + simulationJob->SetDependent(m_simulationCompletion); + simulationJob->Start(); + } + //[GFX TODO]: the completion job should start here + } + void Scene::Simulate([[maybe_unused]] const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) { AZ_PROFILE_SCOPE(RPI, "Scene: Simulate"); @@ -353,7 +403,17 @@ namespace AZ m_simulationTime = tickInfo.m_currentGameTime; // If previous simulation job wasn't done, wait for it to finish. - WaitAndCleanCompletionJob(m_simulationCompletion); + if (m_taskGraphActive) + { + WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive); + } + else + { + WaitAndCleanCompletionJob(m_simulationCompletion); + } + + auto taskGraphActiveInterface = AZ::Interface::Get(); + m_taskGraphActive = taskGraphActiveInterface && taskGraphActiveInterface->IsTaskGraphActive(); if (jobPolicy == RHI::JobPolicy::Serial) { @@ -364,22 +424,27 @@ namespace AZ } else { - // Create a new job to track completion. - m_simulationCompletion = aznew AZ::JobCompletion(); - - for (FeatureProcessorPtr& fp : m_featureProcessors) + if (m_taskGraphActive) { - FeatureProcessor* featureProcessor = fp.get(); - const auto jobLambda = [this, featureProcessor]() - { - featureProcessor->Simulate(m_simulatePacket); - }; - - AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes - simulationJob->SetDependent(m_simulationCompletion); - simulationJob->Start(); + SimulateTaskGraph(); } - //[GFX TODO]: the completion job should start here + else + { + SimulateJobs(); + } + } + } + + void Scene::WaitTGEvent(AZ::TaskGraphEvent& completionTGEvent, AZStd::atomic_bool* workToWaitOn ) + { + AZ_PROFILE_SCOPE(RPI, "Scene: WaitAndCleanCompletionJob"); + if (!workToWaitOn || workToWaitOn->load()) + { + completionTGEvent.Wait(); + } + if (workToWaitOn) + { + workToWaitOn->store(false); } } @@ -394,7 +459,7 @@ namespace AZ completionJob = nullptr; } } - + void Scene::ConnectEvent(PrepareSceneSrgEvent::Handler& handler) { handler.Connect(m_prepareSrgEvent); @@ -418,12 +483,139 @@ namespace AZ } } + void Scene::CollectDrawPacketsTaskGraph() + { + AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets"); + AZ::TaskGraphEvent collectDrawPacketsTGEvent; + static const AZ::TaskDescriptor collectDrawPacketsTGDesc{"RPI_Scene_PrepareRender_CollectDrawPackets", "Graphics"}; + + AZ::TaskGraph collectDrawPacketsTG; + // Launch FeatureProcessor::Render() jobs + for (auto& fp : m_featureProcessors) + { + collectDrawPacketsTG.AddTask( + collectDrawPacketsTGDesc, + [this, &fp]() + { + fp->Render(m_renderPacket); + }); + + } + collectDrawPacketsTG.Submit(&collectDrawPacketsTGEvent); + + // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs if m_parallelOctreeTraversal) + bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal; + m_cullingScene->BeginCulling(m_renderPacket.m_views); + AZ::JobCompletion processCullablesCompletion; + for (ViewPtr& viewPtr : m_renderPacket.m_views) + { + AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob) + { + m_cullingScene->ProcessCullables(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job + }, + true, nullptr); //auto-deletes + if (parallelOctreeTraversal) + { + processCullablesJob->SetDependent(&processCullablesCompletion); + processCullablesJob->Start(); + } + else + { + processCullablesJob->StartAndWaitForCompletion(); + } + } + + WaitTGEvent(collectDrawPacketsTGEvent); + processCullablesCompletion.StartAndWaitForCompletion(); + } + + void Scene::CollectDrawPacketsJobs() + { + AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets"); + AZ::JobCompletion* collectDrawPacketsCompletion = aznew AZ::JobCompletion(); + + // Launch FeatureProcessor::Render() jobs + for (auto& fp : m_featureProcessors) + { + const auto renderLambda = [this, &fp]() + { + fp->Render(m_renderPacket); + }; + + AZ::Job* renderJob = AZ::CreateJobFunction(AZStd::move(renderLambda), true, nullptr); //auto-deletes + renderJob->SetDependent(collectDrawPacketsCompletion); + renderJob->Start(); + } + + // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs) + m_cullingScene->BeginCulling(m_renderPacket.m_views); + for (ViewPtr& viewPtr : m_renderPacket.m_views) + { + AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob) + { + m_cullingScene->ProcessCullables(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job + }, + true, nullptr); //auto-deletes + if (m_cullingScene->GetDebugContext().m_parallelOctreeTraversal) + { + processCullablesJob->SetDependent(collectDrawPacketsCompletion); + processCullablesJob->Start(); + } + else + { + processCullablesJob->StartAndWaitForCompletion(); + } + } + + WaitAndCleanCompletionJob(collectDrawPacketsCompletion); + } + + void Scene::FinalizeDrawListsTaskGraph() + { + AZ::TaskGraphEvent finalizeDrawListsTGEvent; + static const AZ::TaskDescriptor finalizeDrawListsTGDesc{"RPI_Scene_PrepareRender_FinalizeDrawLists", "Graphics"}; + + AZ::TaskGraph finalizeDrawListsTG; + for (auto& view : m_renderPacket.m_views) + { + finalizeDrawListsTG.AddTask( + finalizeDrawListsTGDesc, + [view]() + { + view->FinalizeDrawLists(); + }); + } + finalizeDrawListsTG.Submit(&finalizeDrawListsTGEvent); + WaitTGEvent(finalizeDrawListsTGEvent); + } + + void Scene::FinalizeDrawListsJobs() + { + AZ::JobCompletion* finalizeDrawListsCompletion = aznew AZ::JobCompletion(); + for (auto& view : m_renderPacket.m_views) + { + const auto finalizeDrawListsLambda = [view]() + { + view->FinalizeDrawLists(); + }; + + AZ::Job* finalizeDrawListsJob = AZ::CreateJobFunction(AZStd::move(finalizeDrawListsLambda), true, nullptr); //auto-deletes + finalizeDrawListsJob->SetDependent(finalizeDrawListsCompletion); + finalizeDrawListsJob->Start(); + } + WaitAndCleanCompletionJob(finalizeDrawListsCompletion); + } + void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) { AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender"); + if (m_taskGraphActive) + { + WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive); + } + else { - AZ_PROFILE_SCOPE(RPI, "WaitForSimulationCompletion"); WaitAndCleanCompletionJob(m_simulationCompletion); } @@ -496,44 +688,16 @@ namespace AZ } { - AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets"); - AZ::JobCompletion* collectDrawPacketsCompletion = aznew AZ::JobCompletion(); - // Launch FeatureProcessor::Render() jobs - for (auto& fp : m_featureProcessors) + if (m_taskGraphActive) { - const auto renderLambda = [this, &fp]() - { - fp->Render(m_renderPacket); - }; - - AZ::Job* renderJob = AZ::CreateJobFunction(AZStd::move(renderLambda), true, nullptr); //auto-deletes - renderJob->SetDependent(collectDrawPacketsCompletion); - renderJob->Start(); + CollectDrawPacketsTaskGraph(); } - - // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs) - m_cullingScene->BeginCulling(m_renderPacket.m_views); - for (ViewPtr& viewPtr : m_renderPacket.m_views) + else { - AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob) - { - m_cullingScene->ProcessCullables(*this, *viewPtr, thisJob); - }, - true, nullptr); //auto-deletes - if (m_cullingScene->GetDebugContext().m_parallelOctreeTraversal) - { - processCullablesJob->SetDependent(collectDrawPacketsCompletion); - processCullablesJob->Start(); - } - else - { - processCullablesJob->StartAndWaitForCompletion(); - } + CollectDrawPacketsJobs(); } - WaitAndCleanCompletionJob(collectDrawPacketsCompletion); - m_cullingScene->EndCulling(); // Add dynamic draw data for all the views @@ -556,20 +720,15 @@ namespace AZ } else { - AZ::JobCompletion* finalizeDrawListsCompletion = aznew AZ::JobCompletion(); - for (auto& view : m_renderPacket.m_views) + if (m_taskGraphActive) { - const auto finalizeDrawListsLambda = [view]() - { - view->FinalizeDrawLists(); - }; - - AZ::Job* finalizeDrawListsJob = AZ::CreateJobFunction(AZStd::move(finalizeDrawListsLambda), true, nullptr); //auto-deletes - finalizeDrawListsJob->SetDependent(finalizeDrawListsCompletion); - finalizeDrawListsJob->Start(); + FinalizeDrawListsTaskGraph(); + } + else + { + FinalizeDrawListsJobs(); } AZ_PROFILE_END(RPI); - WaitAndCleanCompletionJob(finalizeDrawListsCompletion); } } diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/001_DefaultWhite.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/001_DefaultWhite.material index 8fe732cb09..2e4eee7f8e 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/001_DefaultWhite.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/001_DefaultWhite.material @@ -1,6 +1,6 @@ { "description": "", - "materialType": "Materials\\Types\\StandardPBR.materialtype", + "materialType": "Materials/Types/StandardPBR.materialtype", "parentMaterial": "", "propertyLayoutVersion": 3 -} +} \ No newline at end of file diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/002_BaseColorLerp.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/002_BaseColorLerp.material index 8509e08d78..f8214e1b2e 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/002_BaseColorLerp.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/002_BaseColorLerp.material @@ -1,6 +1,6 @@ { "description": "", - "materialType": "Materials\\Types\\StandardPBR.materialtype", + "materialType": "Materials/Types/StandardPBR.materialtype", "parentMaterial": "", "propertyLayoutVersion": 3, "properties": { @@ -16,4 +16,4 @@ "textureMap": "TestData/Textures/TextureHaven/4k_castle_brick_02_red/4k_castle_brick_02_red_hp_bc.png" } } -} +} \ No newline at end of file From 79dea539c40729a5d148479efb93e89f750529dd Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Mon, 26 Jul 2021 13:28:54 -0500 Subject: [PATCH 100/115] Allow user to specify a partial gpu name to the forceAdaptor command line argument Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp | 16 +++++++++++----- .../Source/RPI.Private/RPISystemComponent.cpp | 1 + .../RPI/Code/Source/RPI.Public/RPISystem.cpp | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp index ad3ab119ef..bf29efc644 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp @@ -18,6 +18,7 @@ #include #include #include +#include AZ_DEFINE_BUDGET(RHI); @@ -101,6 +102,8 @@ namespace AZ } AZStd::string preferredUserAdapterName = RHI::GetCommandLineValue("forceAdapter"); + AZStd::to_lower(preferredUserAdapterName.begin(), preferredUserAdapterName.end()); + bool findPreferredUserDevice = preferredUserAdapterName.size() > 0; RHI::PhysicalDevice* preferredUserDevice{}; RHI::PhysicalDevice* preferredVendorDevice{}; @@ -110,12 +113,15 @@ namespace AZ const RHI::PhysicalDeviceDescriptor& descriptor = physicalDevice->GetDescriptor(); AZ_Printf("RHISystem", "\tEnumerated physical device: %s\n", descriptor.m_description.c_str()); - - if (!preferredUserDevice && descriptor.m_description == preferredUserAdapterName) + if (findPreferredUserDevice) { - preferredUserDevice = physicalDevice.get(); + AZStd::string descriptorLowerCase = descriptor.m_description; + AZStd::to_lower( descriptorLowerCase.begin(), descriptorLowerCase.end()); + if (!preferredUserDevice && descriptorLowerCase.contains(preferredUserAdapterName)) + { + preferredUserDevice = physicalDevice.get(); + } } - // Record the first nVidia or AMD device we find. if (!preferredVendorDevice && (descriptor.m_vendorId == RHI::VendorId::AMD || descriptor.m_vendorId == RHI::VendorId::nVidia)) { @@ -123,7 +129,7 @@ namespace AZ } } - AZ_Warning("RHISystem", preferredUserAdapterName.empty() || preferredUserDevice, "Specified adapter name not found: '%s'", preferredUserAdapterName.c_str()); + AZ_Warning("RHI", preferredUserAdapterName.empty() || preferredUserDevice, "Specified adapter name not found: '%s'", preferredUserAdapterName.c_str()); RHI::PhysicalDevice* physicalDeviceFound{}; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp index 2567d221e5..8c78ff0e73 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp @@ -56,6 +56,7 @@ namespace AZ void RPISystemComponent::GetRequiredServices(ComponentDescriptor::DependencyArrayType& required) { required.push_back(RHI::Factory::GetComponentService()); + required.push_back(AZ_CRC_CE("LoggerService")); } void RPISystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index 5df1c655d6..5e57ba4e00 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -79,6 +79,7 @@ namespace AZ void RPISystem::Initialize(const RPISystemDescriptor& rpiSystemDescriptor) { + AZ_Printf("RHI", "RPISystem Initialize\n"); m_rhiSystem.InitDevice(); // Gather asset handlers from sub-systems. From de224d236007f74f77c4ee905a26aaf88e316c9b Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Thu, 30 Sep 2021 17:45:29 -0500 Subject: [PATCH 101/115] Removed minor string differences Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp | 2 +- Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp index bf29efc644..744b688c60 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp @@ -129,7 +129,7 @@ namespace AZ } } - AZ_Warning("RHI", preferredUserAdapterName.empty() || preferredUserDevice, "Specified adapter name not found: '%s'", preferredUserAdapterName.c_str()); + AZ_Warning("RHISystem", preferredUserAdapterName.empty() || preferredUserDevice, "Specified adapter name not found: '%s'", preferredUserAdapterName.c_str()); RHI::PhysicalDevice* physicalDeviceFound{}; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index 5e57ba4e00..5df1c655d6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -79,7 +79,6 @@ namespace AZ void RPISystem::Initialize(const RPISystemDescriptor& rpiSystemDescriptor) { - AZ_Printf("RHI", "RPISystem Initialize\n"); m_rhiSystem.InitDevice(); // Gather asset handlers from sub-systems. From 04d62ae76171c6d79d0fdc3d496532f5a4d98f04 Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Thu, 30 Sep 2021 15:59:06 -0700 Subject: [PATCH 102/115] Passed DiffuseProbeGrid OBB directly into culling data. Signed-off-by: dmcdiar --- .../Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp index a966eaddcb..b4f91e58d9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp @@ -831,7 +831,7 @@ namespace AZ aabbWs.GetAsSphere(center, radius); m_cullable.m_cullData.m_boundingSphere = Sphere(center, radius); - m_cullable.m_cullData.m_boundingObb = aabbWs.GetTransformedObb(AZ::Transform::CreateIdentity()); + m_cullable.m_cullData.m_boundingObb = m_obbWs; m_cullable.m_cullData.m_visibilityEntry.m_boundingVolume = aabbWs; m_cullable.m_cullData.m_visibilityEntry.m_userData = &m_cullable; m_cullable.m_cullData.m_visibilityEntry.m_typeFlags = AzFramework::VisibilityEntry::TYPE_RPI_Cullable; From 0b718d435c63e5f3f5f16f5d64be7be559b18c55 Mon Sep 17 00:00:00 2001 From: Mike Chang Date: Thu, 30 Sep 2021 17:40:34 -0700 Subject: [PATCH 103/115] Installer, bootstrapper, and executable signing for Windows (#4406) * Added a codesigning script to pre and post build steps in the Windows installer CD job * Changed `windows_installer` job name to `installer_vs2019` * Added `installer-nightly` tag for `installer_vs2019` * Updated `build_config.json` to use an envvar for the installer url and bucket Signed-off-by: Mike Chang --- .../Platform/Windows/PackagingPostBuild.cmake | 44 ++++++++- .../Platform/Windows/PackagingPreBuild.cmake | 37 +++++++ .../Platform/Windows/Packaging_windows.cmake | 5 +- .../build/Platform/Windows/build_config.json | 12 ++- scripts/signer/Platform/Windows/signer.ps1 | 99 +++++++++++++++++++ 5 files changed, 189 insertions(+), 8 deletions(-) create mode 100644 cmake/Platform/Windows/PackagingPreBuild.cmake create mode 100644 scripts/signer/Platform/Windows/signer.ps1 diff --git a/cmake/Platform/Windows/PackagingPostBuild.cmake b/cmake/Platform/Windows/PackagingPostBuild.cmake index 5e09743373..377a9fb221 100644 --- a/cmake/Platform/Windows/PackagingPostBuild.cmake +++ b/cmake/Platform/Windows/PackagingPostBuild.cmake @@ -32,6 +32,9 @@ set(_addtional_defines -dCPACK_RESOURCE_PATH=${CPACK_SOURCE_DIR}/Platform/Windows/Packaging ) +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) +file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) + if(CPACK_LICENSE_URL) list(APPEND _addtional_defines -dCPACK_LICENSE_URL=${CPACK_LICENSE_URL}) endif() @@ -55,6 +58,30 @@ set(_light_command -o "${_bootstrap_output_file}" ) +set(_signing_command + psexec.exe + -accepteula + -nobanner + -s + powershell.exe + -NoLogo + -ExecutionPolicy Bypass + -File ${_sign_script} +) + +message(STATUS "Signing package files in ${_cpack_wix_out_dir}") +execute_process( + COMMAND ${_signing_command} -packagePath ${_cpack_wix_out_dir} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE +) + +if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing package files. ${_signing_errors}") +endif() + message(STATUS "Creating Bootstrap Installer...") execute_process( COMMAND ${_candle_command} @@ -80,6 +107,19 @@ file(COPY ${_bootstrap_output_file} message(STATUS "Bootstrap installer generated to ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename}") +message(STATUS "Signing bootstrap installer in ${CPACK_PACKAGE_DIRECTORY}") +execute_process( + COMMAND ${_signing_command} -bootstrapPath ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE +) + +if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing bootstrap installer. ${_signing_errors}") +endif() + # use the internal default path if somehow not specified from cpack_configure_downloads if(NOT CPACK_UPLOAD_DIRECTORY) set(CPACK_UPLOAD_DIRECTORY ${CPACK_PACKAGE_DIRECTORY}/CPackUploads) @@ -100,11 +140,9 @@ if(NOT CPACK_UPLOAD_URL) return() endif() -file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) - +file(TO_NATIVE_PATH "${_cpack_wix_out_dir}" _cpack_wix_out_dir) file(TO_NATIVE_PATH "${_root_path}/python/python.cmd" _python_cmd) file(TO_NATIVE_PATH "${_root_path}/scripts/build/tools/upload_to_s3.py" _upload_script) -file(TO_NATIVE_PATH "${_cpack_wix_out_dir}" _cpack_wix_out_dir) function(upload_to_s3 in_url in_local_path in_file_regex) diff --git a/cmake/Platform/Windows/PackagingPreBuild.cmake b/cmake/Platform/Windows/PackagingPreBuild.cmake new file mode 100644 index 0000000000..d3924c7a02 --- /dev/null +++ b/cmake/Platform/Windows/PackagingPreBuild.cmake @@ -0,0 +1,37 @@ +# +# 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 +# +# + +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) +set(_cpack_wix_out_dir ${CPACK_TOPLEVEL_DIRECTORY}) +file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) + +set(_signing_command + psexec.exe + -accepteula + -nobanner + -s + powershell.exe + -NoLogo + -ExecutionPolicy Bypass + -File ${_sign_script} +) + +message(STATUS "Signing executable files in ${_cpack_wix_out_dir}") +execute_process( + COMMAND ${_signing_command} -exePath ${_cpack_wix_out_dir} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE +) + +if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing executable files. ${_signing_errors}") +endif() + +message(STATUS "Signing exes complete!") diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 5bb9928b61..ced7757852 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -108,7 +108,6 @@ set(_raw_text_license [[ ]]) if(LY_INSTALLER_DOWNLOAD_URL) - set(WIX_THEME_WARNING_IMAGE ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/warning.png) if(LY_INSTALLER_LICENSE_URL) @@ -138,6 +137,10 @@ if(LY_INSTALLER_DOWNLOAD_URL) # the bootstrapper will at the very least need a different upgrade guid generate_wix_guid(CPACK_WIX_BOOTSTRAP_UPGRADE_GUID "${_guid_seed_base}_Bootstrap_UpgradeCode") + set(CPACK_PRE_BUILD_SCRIPTS + ${CPACK_SOURCE_DIR}/Platform/Windows/PackagingPreBuild.cmake + ) + set(CPACK_POST_BUILD_SCRIPTS ${CPACK_SOURCE_DIR}/Platform/Windows/PackagingPostBuild.cmake ) diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index 3848e6f980..e33025a4d9 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -351,17 +351,21 @@ "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" } }, - "windows_installer": { + "installer_vs2019": { "TAGS": [ - "nightly-clean" + "nightly-clean", + "nightly-installer" ], + "PIPELINE_ENV":{ + "NODE_LABEL":"windows-packaging" + }, "COMMAND": "build_installer_windows.cmd", "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX! \"", - "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=https://www.o3debinaries.org -DLY_INSTALLER_LICENSE_URL=https://www.o3debinaries.org/license", - "CPACK_BUCKET": "spectra-prism-staging-us-west-2", + "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=!INSTALLER_DOWNLOAD_URL! -DLY_INSTALLER_LICENSE_URL=!INSTALLER_DOWNLOAD_URL!/license", + "CPACK_BUCKET": "!INSTALLER_BUCKET!", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/signer/Platform/Windows/signer.ps1 b/scripts/signer/Platform/Windows/signer.ps1 new file mode 100644 index 0000000000..5366564140 --- /dev/null +++ b/scripts/signer/Platform/Windows/signer.ps1 @@ -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 +# +# + +param ( + [String[]] $exePath, + [String[]] $packagePath, + [String[]] $bootstrapPath, + [String[]] $certificate +) + +# Get prerequisites, certs, and paths ready +$tempPath = [System.IO.Path]::GetTempPath() # Order of operations defined here: https://docs.microsoft.com/en-us/dotnet/api/system.io.path.gettemppath?view=net-5.0&tabs=windows#remarks +$certThumbprint = Get-ChildItem -Path Cert:LocalMachine\MY -CodeSigningCert -ErrorAction Stop | Select-Object -ExpandProperty Thumbprint # Grab first certificate from local machine store + +if ($certificate) { + Write-Output "Checking certificate thumbprint $certificate" + Get-ChildItem -Path Cert:LocalMachine\MY -ErrorAction SilentlyContinue | Where-Object {$_.Thumbprint -eq $certificate} # Prints certificate Thumbprint and Subject if found + if($?) { + $certThumbprint = $certificate + } + else { + Write-Error "$certificate thumbprint not found, using $certThumbprint thumbprint instead" + } +} + +Try { + $signtoolPath = Resolve-Path "C:\Program Files*\Windows Kits\10\bin\*\x64\signtool.exe" -ErrorAction Stop | Select-Object -Last 1 -ExpandProperty Path + $insigniaPath = Resolve-Path "C:\Program Files*\WiX*\bin\insignia.exe" -ErrorAction Stop | Select-Object -Last 1 -ExpandProperty Path +} +Catch { + Write-Error "Signtool or Wix insignia not found! Exiting." +} + +function Write-Signature { + param ( + $signtool, + $thumbprint, + $filename + ) + + $attempts = 2 + $sleepSec = 5 + + Do { + $attempts-- + Try { + & $signtool sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /sha1 $thumbprint /sm $filename + & $signtool verify /pa /v $filename + return + } + Catch { + Write-Error $_.Exception.InnerException.Message -ErrorAction Continue + Start-Sleep -Seconds $sleepSec + } + } while ($attempts -lt 0) + + throw "Failed to sign $filename" # Bypassed in try block if the command is successful +} + +# Looping through each path insteaad of globbing to prevent hitting maximum command string length limit +if ($exePath) { + Write-Output "### Signing EXE files ###" + $files = @(Get-ChildItem $exePath -Recurse *.exe | % { $_.FullName }) + foreach ($file in $files) { + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + } +} + +if ($packagePath) { + Write-Output "### Signing CAB files ###" + $files = @(Get-ChildItem $packagePath -Recurse *.cab | % { $_.FullName }) + foreach ($file in $files) { + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + } + + Write-Output "### Signing MSI files ###" + $files = @(Get-ChildItem $packagePath -Recurse *.msi | % { $_.FullName }) + foreach ($file in $files) { + & $insigniaPath -im $files + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + } +} + +if ($bootstrapPath) { + Write-Output "### Signing bootstrapper EXE ###" + $files = @(Get-ChildItem $bootstrapPath -Recurse *.exe | % { $_.FullName }) + foreach ($file in $files) { + & $insigniaPath -ib $file -o $tempPath\engine.exe + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $tempPath\engine.exe + & $insigniaPath -ab $tempPath\engine.exe $file -o $file + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + Remove-Item -Force $tempPath\engine.exe + } +} \ No newline at end of file From 46ad2f684b80443289469238b3feb803603e336d Mon Sep 17 00:00:00 2001 From: jromnoa Date: Thu, 30 Sep 2021 18:35:01 -0700 Subject: [PATCH 104/115] fixes the configurtion typo to be configuration instead and increases the test timeout to 60 sec from 30 sec Signed-off-by: jromnoa --- AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py | 6 +++--- .../Code/Source/Viewport/MaterialViewportComponent.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py index 249b9c7096..3403d8e9b1 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py @@ -226,9 +226,9 @@ class TestMaterialEditor(object): self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name, cfg_args): """ Tests each valid RHI option (Null RHI excluded) can be launched with the MaterialEditor. - Checks for the "Finished loading viewport configurtions." success message post lounch. + Checks for the "Finished loading viewport configurations." success message post launch. """ - expected_lines = ["Finished loading viewport configurtions."] + expected_lines = ["Finished loading viewport configurations."] unexpected_lines = [ # "Trace::Assert", # "Trace::Error", @@ -241,7 +241,7 @@ class TestMaterialEditor(object): generic_launcher, editor_script="", run_python="--runpython", - timeout=30, + timeout=60, expected_lines=expected_lines, unexpected_lines=unexpected_lines, halt_on_unexpected=False, diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp index 24e78b5ad3..64fd7dff29 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp @@ -271,7 +271,7 @@ namespace MaterialEditor MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnEndReloadContent); - AZ_TracePrintf("Material Editor", "Finished loading viewport configurtions.\n"); + AZ_TracePrintf("Material Editor", "Finished loading viewport configurations.\n"); } AZ::Render::LightingPresetPtr MaterialViewportComponent::AddLightingPreset(const AZ::Render::LightingPreset& preset) From 18652fabeae14ea02a11148d33e99521364b936c Mon Sep 17 00:00:00 2001 From: jromnoa Date: Thu, 30 Sep 2021 18:57:37 -0700 Subject: [PATCH 105/115] fix other configurtion typos to be configuration Signed-off-by: jromnoa --- .../Code/Source/Viewport/MaterialViewportComponent.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp index 64fd7dff29..a8f41917f9 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp @@ -190,7 +190,7 @@ namespace MaterialEditor void MaterialViewportComponent::ReloadContent() { - AZ_TracePrintf("Material Editor", "Started loading viewport configurtions.\n"); + AZ_TracePrintf("Material Editor", "Started loading viewport configurations.\n"); MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnBeginReloadContent); @@ -239,7 +239,7 @@ namespace MaterialEditor { auto presetPtr = AddLightingPreset(*preset); m_lightingPresetLastSavePathMap[presetPtr] = AZ::RPI::AssetUtils::GetSourcePathByAssetId(info.m_assetId); - AZ_TracePrintf("Material Editor", "Loaded viewport configurtion: %s.\n", info.m_relativePath.c_str()); + AZ_TracePrintf("Material Editor", "Loaded viewport configuration: %s.\n", info.m_relativePath.c_str()); } } } @@ -258,7 +258,7 @@ namespace MaterialEditor { auto presetPtr = AddModelPreset(*preset); m_modelPresetLastSavePathMap[presetPtr] = AZ::RPI::AssetUtils::GetSourcePathByAssetId(info.m_assetId); - AZ_TracePrintf("Material Editor", "Loaded viewport configurtion: %s.\n", info.m_relativePath.c_str()); + AZ_TracePrintf("Material Editor", "Loaded viewport configuration: %s.\n", info.m_relativePath.c_str()); } } } From 41dbf69b46327089e95e74557f17fc42075115b0 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Fri, 1 Oct 2021 09:59:11 +0200 Subject: [PATCH 106/115] Animation Editor: Move real-time plugin updates from SystemComponent to the main window (#4384) Untangled the system component from editor ticking dependencies and moved it to the main window which is the more logical place for it. Signed-off-by: Benjamin Jillich --- .../EMStudioSDK/Source/MainWindow.cpp | 60 +++++++++++++++-- .../EMStudioSDK/Source/MainWindow.h | 14 +++- .../Integration/System/SystemComponent.cpp | 65 ++----------------- .../Integration/System/SystemComponent.h | 1 - 4 files changed, 74 insertions(+), 66 deletions(-) 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 8ca4e1de81..06088790d9 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp @@ -69,6 +69,9 @@ AZ_PUSH_DISABLE_WARNING(4267, "-Wconversion") AZ_POP_DISABLE_WARNING #include +#include +#include + namespace EMStudio { class SaveDirtyWorkspaceCallback @@ -257,10 +260,10 @@ namespace EMStudio m_saveWorkspaceCallback = nullptr; } - - // destructor MainWindow::~MainWindow() { + DisableUpdatingPlugins(); + if (m_nativeEventFilter) { QAbstractEventDispatcher::instance()->removeNativeEventFilter(m_nativeEventFilter); @@ -577,6 +580,8 @@ namespace EMStudio AZ_Assert(!m_nativeEventFilter, "Double initialization?"); m_nativeEventFilter = new NativeEventFilter(this); QAbstractEventDispatcher::instance()->installNativeEventFilter(m_nativeEventFilter); + + EnableUpdatingPlugins(); } MainWindow::MainWindowCommandManagerCallback::MainWindowCommandManagerCallback() @@ -2813,6 +2818,53 @@ namespace EMStudio } } -} // namespace EMStudio + void MainWindow::UpdatePlugins(float timeDelta) + { + EMStudio::PluginManager* pluginManager = EMStudio::GetPluginManager(); + if (!pluginManager) + { + return; + } -#include + const size_t numPlugins = pluginManager->GetNumActivePlugins(); + for (size_t i = 0; i < numPlugins; ++i) + { + EMStudio::EMStudioPlugin* plugin = pluginManager->GetActivePlugin(i); + plugin->ProcessFrame(timeDelta); + } + } + + void MainWindow::EnableUpdatingPlugins() + { + AZ::TickBus::Handler::BusConnect(); + } + + void MainWindow::DisableUpdatingPlugins() + { + AZ::TickBus::Handler::BusDisconnect(); + } + + void MainWindow::OnTick(float delta, AZ::ScriptTimePoint timePoint) + { + AZ_UNUSED(timePoint); + + // Check if we are in game mode. + IEditor* editor = nullptr; + AzToolsFramework::EditorRequestBus::BroadcastResult(editor, &AzToolsFramework::EditorRequests::GetEditor); + const bool inGameMode = editor ? editor->IsInGameMode() : false; + + // Update all the animation editor plugins (redraw viewports, timeline, and graph windows etc). + // But only update this when the main window is visible and we are in game mode. + const bool isEditorActive = !visibleRegion().isEmpty() && !inGameMode; + + if (isEditorActive) + { + UpdatePlugins(delta); + } + } + + int MainWindow::GetTickOrder() + { + return AZ::TICK_UI; + } +} // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h index a11f11c6a8..585101f7d2 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h @@ -9,6 +9,7 @@ #pragma once #if !defined(Q_MOC_RUN) +#include #include #include #include @@ -99,8 +100,9 @@ namespace EMStudio : public AzQtComponents::DockMainWindow , private PluginOptionsNotificationsBus::Router , public EMotionFX::ActorEditorRequestBus::Handler + , private AZ::TickBus::Handler { - Q_OBJECT + Q_OBJECT // AUTOMOC MCORE_MEMORYOBJECTCATEGORY(MainWindow, MCore::MCORE_DEFAULT_ALIGNMENT, MEMCATEGORY_EMSTUDIOSDK) public: @@ -304,6 +306,16 @@ namespace EMStudio MainWindowCommandManagerCallback m_mainWindowCommandManagerCallback; + private: + // AZ::TickBus::Handler overrides + void OnTick(float delta, AZ::ScriptTimePoint timePoint) override; + int GetTickOrder() override; + + void UpdatePlugins(float timeDelta); + + void EnableUpdatingPlugins(); + void DisableUpdatingPlugins(); + public slots: void OnFileOpenActor(); void OnFileSaveSelectedActors(); diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp index 56c22bb1ff..0f87c488b9 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp @@ -62,7 +62,6 @@ #if defined(EMOTIONFXANIMATION_EDITOR) // EMFX tools / editor includes -# include // Qt # include // EMStudio tools and main window registration @@ -603,31 +602,6 @@ namespace EMotionFX #endif } - ////////////////////////////////////////////////////////////////////////// -#if defined (EMOTIONFXANIMATION_EDITOR) - void SystemComponent::UpdateAnimationEditorPlugins(float delta) - { - if (!EMStudio::GetManager()) - { - return; - } - - EMStudio::PluginManager* pluginManager = EMStudio::GetPluginManager(); - if (!pluginManager) - { - return; - } - - // Process the plugins. - const size_t numPlugins = pluginManager->GetNumActivePlugins(); - for (size_t i = 0; i < numPlugins; ++i) - { - EMStudio::EMStudioPlugin* plugin = pluginManager->GetActivePlugin(i); - plugin->ProcessFrame(delta); - } - } -#endif - ////////////////////////////////////////////////////////////////////////// void SystemComponent::OnTick(float delta, AZ::ScriptTimePoint timePoint) { @@ -635,47 +609,18 @@ namespace EMotionFX #if defined (EMOTIONFXANIMATION_EDITOR) AZ_UNUSED(delta); - const float realDelta = m_updateTimer.StampAndGetDeltaTimeInSeconds(); + delta = m_updateTimer.StampAndGetDeltaTimeInSeconds(); +#endif // Flush events prior to updating EMotion FX. ActorNotificationBus::ExecuteQueuedEvents(); - if (CVars::emfx_updateEnabled) - { - // Main EMotionFX runtime update. - GetEMotionFX().Update(realDelta); - } - - // Check if we are in game mode. - IEditor* editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - const bool inGameMode = editor ? editor->IsInGameMode() : false; - - // Update all the animation editor plugins (redraw viewports, timeline, and graph windows etc). - // But only update this when the main window is visible and we are in game mode. - const bool isEditorActive = - EMotionFX::GetEMotionFX().GetIsInEditorMode() && - EMStudio::GetManager() && - EMStudio::HasMainWindow() && - !EMStudio::GetMainWindow()->visibleRegion().isEmpty() && - !inGameMode; - - if (isEditorActive) - { - UpdateAnimationEditorPlugins(realDelta); - } -#else - // Flush events prior to updating EMotion FX. - ActorNotificationBus::ExecuteQueuedEvents(); - if (CVars::emfx_updateEnabled) { // Main EMotionFX runtime update. GetEMotionFX().Update(delta); } -#endif - const float timeDelta = delta; const ActorManager* actorManager = GetEMotionFX().GetActorManager(); const size_t numActorInstances = actorManager->GetNumActorInstances(); for (size_t i = 0; i < numActorInstances; ++i) @@ -704,7 +649,7 @@ namespace EMotionFX // If we have a physics controller. if (hasCustomMotionExtractionController || hasPhysicsController) { - const float deltaTimeInv = (timeDelta > 0.0f) ? (1.0f / timeDelta) : 0.0f; + const float deltaTimeInv = (delta > 0.0f) ? (1.0f / delta) : 0.0f; AZ::Transform currentTransform = AZ::Transform::CreateIdentity(); AZ::TransformBus::EventResult(currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); @@ -719,7 +664,7 @@ namespace EMotionFX } else if (hasCustomMotionExtractionController) { - MotionExtractionRequestBus::Event(entityId, &MotionExtractionRequestBus::Events::ExtractMotion, positionDelta, timeDelta); + MotionExtractionRequestBus::Event(entityId, &MotionExtractionRequestBus::Events::ExtractMotion, positionDelta, delta); AZ::TransformBus::EventResult(currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); } @@ -884,7 +829,7 @@ namespace EMotionFX // Register EMotionFX window with the main editor. AzToolsFramework::ViewPaneOptions emotionFXWindowOptions; - emotionFXWindowOptions.isPreview = true; + emotionFXWindowOptions.isPreview = false; emotionFXWindowOptions.isDeletable = true; emotionFXWindowOptions.isDockable = false; #if AZ_TRAIT_EMOTIONFX_MAIN_WINDOW_DETACHED diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h index a716f0aa9b..5e30820ca3 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h @@ -108,7 +108,6 @@ namespace EMotionFX void SetMediaRoot(const char* alias); #if defined (EMOTIONFXANIMATION_EDITOR) - void UpdateAnimationEditorPlugins(float delta); void NotifyRegisterViews() override; bool IsSystemActive(EditorAnimationSystemRequests::AnimationSystem systemType) override; From fec77632efbc437394580744de0db76d917a8c85 Mon Sep 17 00:00:00 2001 From: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Date: Fri, 1 Oct 2021 10:15:16 -0500 Subject: [PATCH 107/115] Archive Component - Rewrite and additional work on Archive and Asset Bundler (#4332) * Fix issues with seedlist for AutomatedTesting Fixes error reporting so it will show the file hint in the tool. Removes any missing assets from the .seed file. Remove an unnecessary dependency from AutomatedTesting dependencies file. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Make ArchiveComponent use AZ::IO::IArchive Initial changes that will get the sychronous calls in ArchiveComponent to use IArchive interface rather than external zip/7z tools. Some of the asynchronous api are still in place, anything that wasn't being used has been removed for now. This may change later if we move towards all the api being asynchronous. Until then, we can't remove the reliance upon the external archive tools completely. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Updates AZStd::thread constructors Adds a variadic constructor which forwards args to the functor. Because of our thread_desc extension, there was confusion on the arugments, so the args were reordered to take the thread_desc first, before the functor and args. Also the thread_desc is taken as reference rather than by pointer. Update callsites to account for this change. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Async operation of ArchiveComponent api This sets up the ArchiveComponent to operate asynchronously. It uses promise/future to transfer results to caller. This is still broken, there's a few things that need to get fixed up, but this is a good checkpoint for the work as it solidifies the api, cleans up a bunch of unused code, and compiles. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Removes the platform-specific ArchiveComponen These are no longer needed, as they control the direct interaction with host OS tools like 7za.exe or /bin/zip. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Removes the platform-specific files from cmake Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Removes the 7za.exe (and legal notice) This tool is no longer needed in the repo. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fixes usage of IArchive::GetFullPath() This changed to return a PathView, updated to reflect that. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix promises and threads Make sure promises are only set exactly once. This meant reworking some of the initial error checking. Detach threads when created. Adds [[nodiscard]] to the functions that return a future. Since threads are detached, the future is the main way to get communication from the thread. Clean up interface, add comments. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * More edits to thread creation Changes to thread construction to account for parameter change. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix some remaining issues with ArchiveComponent Put created threads inside a container, then join them at Deactivate. Fix asset bundler case when injecting a file with no working directory. Fix thread constructor that applies args to a function. Fix lambdas to take string args by value rather than reference. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fixes some remaining bugs in ArchiveComponent Open archive as read-only during extract & list operations. Fixes paths issues. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix initialize of opaque thread handle in thread_UnixLike.h Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed unused variable in AssetBundleComponent.cpp to fix compiler warning Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fix some issues with archives File paths in the CDR and the local headers need to match, but there were issues with path separators and case that made it possible to get invalid headers errors in some archives. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Adds some new ArchiveComponent unit tests Adds new tests for extraction of archive and adding files from a file list to an archive. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix file data offset issues when opening archives When opening an INestedArchive it would run through the CDR headers to create file entries in the zip cache. The offsets to the compressed data were being calculated incorrectly because they were using the CDR headers rather than jumping to the local file headers and getting offsets from those sizes. Removed and refactored some archive validation flow and zip cache factory init methods to either init default or init w/ additional validation checks. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Addresses PR feedback Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Address more points of feedback in PR Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Address additional PR feedback Fixes up some error checks and uses of strings vs paths. Enable archive component tests on Linux so we can see if they will pass. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Address PR feedback Change the INestedArchive interface to list files as AZ::IO::Path. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Disabling the ArchiveComponent tests on Linux They failed so we will revisit them to attempt a fix. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Rename a member variable to be more accurate Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Address feedback on PR Bump version of Archive Components for serialize context. Improve error messages during archive open and validation. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Revert recent changes Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Assets/Engine/SeedAssetList.seed | 904 ------------------ .../AutomatedTesting_Dependencies.xml | 1 - .../AzCore/AzCore/IO/Streamer/Scheduler.cpp | 10 +- .../Jobs/Internal/JobManagerWorkStealing.cpp | 4 +- .../AzCore/AzCore/Task/TaskExecutor.cpp | 6 +- .../AzCore/AzCore/std/parallel/thread.h | 19 +- .../std/parallel/internal/thread_UnixLike.h | 20 +- .../std/parallel/internal/thread_WinAPI.h | 19 +- .../Framework/AzCore/Tests/AZStd/Parallel.cpp | 154 +-- Code/Framework/AzCore/Tests/Memory.cpp | 10 +- .../AzFramework/Application/Application.cpp | 16 +- .../AzFramework/Archive/Archive.cpp | 15 +- .../AzFramework/Archive/INestedArchive.h | 13 + .../AzFramework/Archive/NestedArchive.cpp | 40 + .../AzFramework/Archive/NestedArchive.h | 9 +- .../AzFramework/Archive/ZipDirCache.cpp | 13 +- .../Archive/ZipDirCacheFactory.cpp | 220 ++--- .../AzFramework/Archive/ZipDirCacheFactory.h | 28 +- .../AzFramework/Archive/ZipDirList.cpp | 4 +- .../AzFramework/Archive/ZipDirStructures.h | 35 +- .../Network/AssetProcessorConnection.cpp | 2 +- .../TargetManagementComponent.cpp | 2 +- .../AzNetworking/Utilities/TimedThread.cpp | 38 +- .../AzToolsFramework/Archive/ArchiveAPI.h | 123 ++- .../Archive/ArchiveComponent.cpp | 874 ++++++++++------- .../Archive/ArchiveComponent.h | 90 +- .../Archive/NullArchiveComponent.cpp | 113 +-- .../Archive/NullArchiveComponent.h | 44 +- .../AssetBundle/AssetBundleComponent.cpp | 27 +- .../AssetBundle/AssetBundleComponent.h | 2 +- .../Archive/ArchiveComponent_Linux.cpp | 230 ----- .../Platform/Linux/platform_linux_files.cmake | 1 - .../Archive/ArchiveComponent_Mac.cpp | 263 ----- .../Platform/Mac/platform_mac_files.cmake | 1 - .../Archive/ArchiveComponent_Windows.cpp | 167 ---- .../Windows/platform_windows_files.cmake | 1 - .../AzToolsFramework/Tests/ArchiveTests.cpp | 126 ++- .../GridMate/GridMate/Carrier/Carrier.cpp | 2 +- .../GridMate/Carrier/SocketDriver.cpp | 2 +- .../source/models/SeedListTableModel.cpp | 3 +- .../AssetBuilder/AssetBuilderComponent.cpp | 2 +- .../AssetCatalog/AssetCatalogUnitTests.cpp | 4 +- .../native/utilities/AssetServerHandler.cpp | 24 +- .../RemoteConsole/Core/RemoteConsoleCore.cpp | 2 +- .../RHI/Code/Source/RHI/AsyncWorkQueue.cpp | 2 +- .../Atom/RHI/Code/Source/RHI/CommandQueue.cpp | 2 +- Gems/Atom/RHI/Code/Source/RHI/Fence.cpp | 4 +- .../Shader/ShaderVariantAsyncLoader.cpp | 5 +- .../Code/Source/Engine/AudioSystem.cpp | 2 +- .../Code/Source/BarrierInputClient.cpp | 2 +- .../Code/Source/HttpRequestManager.cpp | 2 +- .../LevelBuilder/LevelBuilderWorker.cpp | 35 +- .../MicrophoneSystemComponent_Windows.cpp | 2 +- .../Code/Tests/PhysXMultithreadingTest.cpp | 2 +- .../Code/Source/SaveDataSystemComponent.cpp | 28 +- Tools/7za.exe | 3 - Tools/7za_legal_notice.txt | 36 - 57 files changed, 1208 insertions(+), 2600 deletions(-) delete mode 100644 Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/Archive/ArchiveComponent_Linux.cpp delete mode 100644 Code/Framework/AzToolsFramework/Platform/Mac/AzToolsFramework/Archive/ArchiveComponent_Mac.cpp delete mode 100644 Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp delete mode 100644 Tools/7za.exe delete mode 100644 Tools/7za_legal_notice.txt diff --git a/Assets/Engine/SeedAssetList.seed b/Assets/Engine/SeedAssetList.seed index 77ec509721..579fd3c444 100644 --- a/Assets/Engine/SeedAssetList.seed +++ b/Assets/Engine/SeedAssetList.seed @@ -64,30 +64,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -160,686 +136,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1384,166 +680,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1632,46 +768,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/AutomatedTesting_Dependencies.xml b/AutomatedTesting/AutomatedTesting_Dependencies.xml index 50a5caea73..98e00a2914 100644 --- a/AutomatedTesting/AutomatedTesting_Dependencies.xml +++ b/AutomatedTesting/AutomatedTesting_Dependencies.xml @@ -1,5 +1,4 @@ - \ No newline at end of file diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp index 9b4996ad49..9ee0fefc99 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp @@ -43,10 +43,12 @@ namespace AZ::IO m_mainLoopDesc = threadDesc; m_mainLoopDesc.m_name = "IO Scheduler"; - m_mainLoop = AZStd::thread([this]() - { - Thread_MainLoop(); - }, &m_mainLoopDesc); + m_mainLoop = AZStd::thread( + m_mainLoopDesc, + [this]() + { + Thread_MainLoop(); + }); } } diff --git a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp index f76946a667..230bf959f6 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp @@ -644,11 +644,11 @@ JobManagerWorkStealing::ThreadList JobManagerWorkStealing::CreateWorkerThreads(c } info->m_thread = AZStd::thread( + threadDesc, [this, info]() { this->ProcessJobsWorker(info); - }, - &threadDesc + } ); info->m_threadId = info->m_thread.get_id(); diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp index d2d19d1359..7da04d7301 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp @@ -205,13 +205,13 @@ namespace AZ } m_active.store(true, AZStd::memory_order_release); - m_thread = AZStd::thread{ [this, &initSemaphore] + m_thread = AZStd::thread{ desc, + [this, &initSemaphore] { t_worker = this; initSemaphore.release(); Run(); - }, - &desc }; + } }; } // Threads that wait on a graph to complete are disqualified from receiving tasks until the wait finishes diff --git a/Code/Framework/AzCore/AzCore/std/parallel/thread.h b/Code/Framework/AzCore/AzCore/std/parallel/thread.h index 15d8c9dc8e..eef269c8ac 100644 --- a/Code/Framework/AzCore/AzCore/std/parallel/thread.h +++ b/Code/Framework/AzCore/AzCore/std/parallel/thread.h @@ -87,12 +87,6 @@ namespace AZStd // construct/copy/destroy: thread(); - /** - * \note thread_desc is AZStd extension. - */ - template - explicit thread(F&& f, const thread_desc* desc = 0); - ~thread(); thread(thread&& rhs) @@ -108,6 +102,15 @@ namespace AZStd return *this; } + template, thread_desc>>> + explicit thread(F&& f, Args&&... args); + + /** + * \note thread_desc is AZStd extension. + */ + template + thread(const thread_desc& desc, F&& f, Args&&... args); + // Till we fully have RVALUES template explicit thread(Internal::thread_move_t f); @@ -138,8 +141,8 @@ namespace AZStd //thread(AZStd::delegate d,const thread_desc* desc = 0); private: - thread(thread&); - thread& operator=(thread&); + thread(const thread&) = delete; + thread& operator=(const thread&) = delete; native_thread_data_type m_thread; }; diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h index 499caebac0..d9a4982a0a 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h @@ -10,6 +10,8 @@ #include #include +#include + namespace AZStd { namespace Internal @@ -22,12 +24,20 @@ namespace AZStd ////////////////////////////////////////////////////////////////////////// // thread - template - inline thread::thread(F&& f, const thread_desc* desc) + template + thread::thread(F&& f, Args&&... args) + : thread(thread_desc{}, AZStd::forward(f), AZStd::forward(args)...) + {} + + template + thread::thread(const thread_desc& desc, F&& f, Args&&... args) { - Internal::thread_info* ti = Internal::create_thread_info(AZStd::forward(f)); - ti->m_name = desc ? desc->m_name : nullptr; - m_thread = Internal::create_thread(desc, ti); + auto threadfunc = [fn = AZStd::forward(f), argsTuple = AZStd::make_tuple(AZStd::forward(args)...)]() mutable -> void + { + AZStd::apply(AZStd::move(fn), AZStd::move(argsTuple)); + }; + Internal::thread_info* ti = Internal::create_thread_info(AZStd::move(threadfunc)); + m_thread = Internal::create_thread(&desc, ti); } inline bool thread::joinable() const diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h index 46986521e7..c79381a74a 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h @@ -18,6 +18,8 @@ extern "C" AZ_DLL_IMPORT unsigned long __stdcall GetCurrentThreadId(void); } +#include + namespace AZStd { namespace Internal @@ -30,11 +32,20 @@ namespace AZStd ////////////////////////////////////////////////////////////////////////// // thread - template - inline thread::thread(F&& f, const thread_desc* desc) + template + thread::thread(F&& f, Args&&... args) + : thread(thread_desc{}, AZStd::forward(f), AZStd::forward(args)...) + {} + + template + thread::thread(const thread_desc& desc, F&& f, Args&&... args) { - Internal::thread_info* ti = Internal::create_thread_info(AZStd::forward(f)); - m_thread.m_handle = Internal::create_thread(desc, ti, &m_thread.m_id); + auto threadfunc = [fn = AZStd::forward(f), argsTuple = AZStd::make_tuple(AZStd::forward(args)...)]() mutable -> void + { + AZStd::apply(AZStd::move(fn), AZStd::move(argsTuple)); + }; + Internal::thread_info* ti = Internal::create_thread_info(AZStd::move(threadfunc)); + m_thread.m_handle = Internal::create_thread(&desc, ti, &m_thread.m_id); } inline bool thread::joinable() const diff --git a/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp b/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp index f3d4f58250..407cd3c258 100644 --- a/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp @@ -195,18 +195,18 @@ namespace UnitTest void test_thread_id_for_running_thread_is_not_default_constructed_id() { - const thread_desc* desc = m_numThreadDesc ? &m_desc[0] : nullptr; - AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc); + const thread_desc desc = m_numThreadDesc ? m_desc[0] : thread_desc{}; + AZStd::thread t(desc, AZStd::bind(&Parallel_Thread::do_nothing, this)); AZ_TEST_ASSERT(t.get_id() != AZStd::thread::id()); t.join(); } void test_different_threads_have_different_ids() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; - const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr; - AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc1); - AZStd::thread t2(AZStd::bind(&Parallel_Thread::do_nothing, this), desc2); + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; + const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{}; + AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::do_nothing, this)); + AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::do_nothing, this)); AZ_TEST_ASSERT(t.get_id() != t2.get_id()); t.join(); t2.join(); @@ -214,13 +214,13 @@ namespace UnitTest void test_thread_ids_have_a_total_order() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; - const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr; - const thread_desc* desc3 = m_numThreadDesc ? &m_desc[2] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; + const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{}; + const thread_desc desc3 = m_numThreadDesc ? m_desc[2] : thread_desc{}; - AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc1); - AZStd::thread t2(AZStd::bind(&Parallel_Thread::do_nothing, this), desc2); - AZStd::thread t3(AZStd::bind(&Parallel_Thread::do_nothing, this), desc3); + AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::do_nothing, this)); + AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::do_nothing, this)); + AZStd::thread t3(desc3, AZStd::bind(&Parallel_Thread::do_nothing, this)); AZ_TEST_ASSERT(t.get_id() != t2.get_id()); AZ_TEST_ASSERT(t.get_id() != t3.get_id()); AZ_TEST_ASSERT(t2.get_id() != t3.get_id()); @@ -313,10 +313,10 @@ namespace UnitTest void test_thread_id_of_running_thread_returned_by_this_thread_get_id() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; AZStd::thread::id id; - AZStd::thread t(AZStd::bind(&Parallel_Thread::get_thread_id, this, &id), desc1); + AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::get_thread_id, this, &id)); AZStd::thread::id t_id = t.get_id(); t.join(); AZ_TEST_ASSERT(id == t_id); @@ -366,10 +366,10 @@ namespace UnitTest void test_move_on_construction() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; AZStd::thread::id the_id; AZStd::thread x; - x = AZStd::thread(AZStd::bind(&Parallel_Thread::do_nothing_id, this, &the_id), desc1); + x = AZStd::thread(desc1, AZStd::bind(&Parallel_Thread::do_nothing_id, this, &the_id)); AZStd::thread::id x_id = x.get_id(); x.join(); AZ_TEST_ASSERT(the_id == x_id); @@ -377,8 +377,8 @@ namespace UnitTest AZStd::thread make_thread(AZStd::thread::id* the_id) { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; - return AZStd::thread(AZStd::bind(&Parallel_Thread::do_nothing_id, this, the_id), desc1); + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; + return AZStd::thread(desc1, AZStd::bind(&Parallel_Thread::do_nothing_id, this, the_id)); } void test_move_from_function_return() @@ -430,9 +430,9 @@ namespace UnitTest void do_test_creation() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; m_data = 0; - AZStd::thread t(AZStd::bind(&Parallel_Thread::simple_thread, this), desc1); + AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::simple_thread, this)); t.join(); AZ_TEST_ASSERT(m_data == 999); } @@ -445,9 +445,9 @@ namespace UnitTest void do_test_id_comparison() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; AZStd::thread::id self = this_thread::get_id(); - AZStd::thread thrd(AZStd::bind(&Parallel_Thread::comparison_thread, this, self), desc1); + AZStd::thread thrd(desc1, AZStd::bind(&Parallel_Thread::comparison_thread, this, self)); thrd.join(); } @@ -476,10 +476,10 @@ namespace UnitTest void do_test_creation_through_reference_wrapper() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; non_copyable_functor f; - AZStd::thread thrd(AZStd::ref(f), desc1); + AZStd::thread thrd(desc1, AZStd::ref(f)); thrd.join(); AZ_TEST_ASSERT(f.value == 999); } @@ -491,10 +491,10 @@ namespace UnitTest void test_swap() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; - const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr; - AZStd::thread t(AZStd::bind(&Parallel_Thread::simple_thread, this), desc1); - AZStd::thread t2(AZStd::bind(&Parallel_Thread::simple_thread, this), desc2); + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; + const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{}; + AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::simple_thread, this)); + AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::simple_thread, this)); AZStd::thread::id id1 = t.get_id(); AZStd::thread::id id2 = t2.get_id(); @@ -512,7 +512,7 @@ namespace UnitTest void run() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; // We need to have at least one processor AZ_TEST_ASSERT(AZStd::thread::hardware_concurrency() >= 1); @@ -520,18 +520,18 @@ namespace UnitTest // Create thread to increment data till we need to m_data = 0; m_dataMax = 10; - AZStd::thread tr(AZStd::bind(&Parallel_Thread::increment_data, this), desc1); + AZStd::thread tr(desc1, AZStd::bind(&Parallel_Thread::increment_data, this)); tr.join(); AZ_TEST_ASSERT(m_data == m_dataMax); m_data = 0; - AZStd::thread trDel(make_delegate(this, &Parallel_Thread::increment_data), desc1); + AZStd::thread trDel(desc1, make_delegate(this, &Parallel_Thread::increment_data)); trDel.join(); AZ_TEST_ASSERT(m_data == m_dataMax); chrono::system_clock::time_point startTime = chrono::system_clock::now(); { - AZStd::thread tr1(AZStd::bind(&Parallel_Thread::sleep_thread, this, chrono::milliseconds(100)), desc1); + AZStd::thread tr1(desc1, AZStd::bind(&Parallel_Thread::sleep_thread, this, chrono::milliseconds(100))); tr1.join(); } auto sleepTime = chrono::system_clock::now() - startTime; @@ -563,71 +563,71 @@ namespace UnitTest { MfTest x; AZStd::function func = AZStd::bind(&MfTest::f0, &x); - AZStd::thread(func, desc1).join(); + AZStd::thread(desc1, func).join(); func = AZStd::bind(&MfTest::f0, AZStd::ref(x)); - AZStd::thread(func, desc1).join(); + AZStd::thread(desc1, func).join(); func = AZStd::bind(&MfTest::g0, &x); - AZStd::thread(func, desc1).join(); + AZStd::thread(desc1, func).join(); func = AZStd::bind(&MfTest::g0, x); - AZStd::thread(func, desc1).join(); + AZStd::thread(desc1, func).join(); func = AZStd::bind(&MfTest::g0, AZStd::ref(x)); - AZStd::thread(func, desc1).join(); + AZStd::thread(desc1, func).join(); //// 1 - //thread( AZStd::bind(&MfTest::f1, &x, 1) , desc1).join(); - //thread( AZStd::bind(&MfTest::f1, AZStd::ref(x), 1) , desc1).join(); - //thread( AZStd::bind(&MfTest::g1, &x, 1) , desc1).join(); - //thread( AZStd::bind(&MfTest::g1, x, 1) , desc1).join(); - //thread( AZStd::bind(&MfTest::g1, AZStd::ref(x), 1) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f1, &x, 1)).join(); + //thread( AZStd::bind(desc1, &MfTest::f1, AZStd::ref(x), 1)).join(); + //thread( AZStd::bind(desc1, &MfTest::g1, &x, 1)).join(); + //thread( AZStd::bind(desc1, &MfTest::g1, x, 1)).join(); + //thread( AZStd::bind(desc1, &MfTest::g1, AZStd::ref(x), 1)).join(); //// 2 - //thread( AZStd::bind(&MfTest::f2, &x, 1, 2) , desc1).join(); - //thread( AZStd::bind(&MfTest::f2, AZStd::ref(x), 1, 2) , desc1).join(); - //thread( AZStd::bind(&MfTest::g2, &x, 1, 2) , desc1).join(); - //thread( AZStd::bind(&MfTest::g2, x, 1, 2) , desc1).join(); - //thread( AZStd::bind(&MfTest::g2, AZStd::ref(x), 1, 2) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f2, &x, 1, 2)).join(); + //thread( AZStd::bind(desc1, &MfTest::f2, AZStd::ref(x), 1, 2)).join(); + //thread( AZStd::bind(desc1, &MfTest::g2, &x, 1, 2)).join(); + //thread( AZStd::bind(desc1, &MfTest::g2, x, 1, 2)).join(); + //thread( AZStd::bind(desc1, &MfTest::g2, AZStd::ref(x), 1, 2)).join(); //// 3 - //thread( AZStd::bind(&MfTest::f3, &x, 1, 2, 3) , desc1).join(); - //thread( AZStd::bind(&MfTest::f3, AZStd::ref(x), 1, 2, 3) , desc1).join(); - //thread( AZStd::bind(&MfTest::g3, &x, 1, 2, 3) , desc1).join(); - //thread( AZStd::bind(&MfTest::g3, x, 1, 2, 3) , desc1).join(); - //thread( AZStd::bind(&MfTest::g3, AZStd::ref(x), 1, 2, 3) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f3, &x, 1, 2, 3)).join(); + //thread( AZStd::bind(desc1, &MfTest::f3, AZStd::ref(x), 1, 2, 3)).join(); + //thread( AZStd::bind(desc1, &MfTest::g3, &x, 1, 2, 3)).join(); + //thread( AZStd::bind(desc1, &MfTest::g3, x, 1, 2, 3)).join(); + //thread( AZStd::bind(desc1, &MfTest::g3, AZStd::ref(x), 1, 2, 3)).join(); //// 4 - //thread( AZStd::bind(&MfTest::f4, &x, 1, 2, 3, 4) , desc1).join(); - //thread( AZStd::bind(&MfTest::f4, AZStd::ref(x), 1, 2, 3, 4) , desc1).join(); - //thread( AZStd::bind(&MfTest::g4, &x, 1, 2, 3, 4) , desc1).join(); - //thread( AZStd::bind(&MfTest::g4, x, 1, 2, 3, 4) , desc1).join(); - //thread( AZStd::bind(&MfTest::g4, AZStd::ref(x), 1, 2, 3, 4) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f4, &x, 1, 2, 3, 4)).join(); + //thread( AZStd::bind(desc1, &MfTest::f4, AZStd::ref(x), 1, 2, 3, 4)).join(); + //thread( AZStd::bind(desc1, &MfTest::g4, &x, 1, 2, 3, 4)).join(); + //thread( AZStd::bind(desc1, &MfTest::g4, x, 1, 2, 3, 4)).join(); + //thread( AZStd::bind(desc1, &MfTest::g4, AZStd::ref(x), 1, 2, 3, 4)).join(); //// 5 - //thread( AZStd::bind(&MfTest::f5, &x, 1, 2, 3, 4, 5) , desc1).join(); - //thread( AZStd::bind(&MfTest::f5, AZStd::ref(x), 1, 2, 3, 4, 5) , desc1).join(); - //thread( AZStd::bind(&MfTest::g5, &x, 1, 2, 3, 4, 5) , desc1).join(); - //thread( AZStd::bind(&MfTest::g5, x, 1, 2, 3, 4, 5) , desc1).join(); - //thread( AZStd::bind(&MfTest::g5, AZStd::ref(x), 1, 2, 3, 4, 5) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f5, &x, 1, 2, 3, 4, 5)).join(); + //thread( AZStd::bind(desc1, &MfTest::f5, AZStd::ref(x), 1, 2, 3, 4, 5)).join(); + //thread( AZStd::bind(desc1, &MfTest::g5, &x, 1, 2, 3, 4, 5)).join(); + //thread( AZStd::bind(desc1, &MfTest::g5, x, 1, 2, 3, 4, 5)).join(); + //thread( AZStd::bind(desc1, &MfTest::g5, AZStd::ref(x), 1, 2, 3, 4, 5)).join(); //// 6 - //thread( AZStd::bind(&MfTest::f6, &x, 1, 2, 3, 4, 5, 6) , desc1).join(); - //thread( AZStd::bind(&MfTest::f6, AZStd::ref(x), 1, 2, 3, 4, 5, 6) , desc1).join(); - //thread( AZStd::bind(&MfTest::g6, &x, 1, 2, 3, 4, 5, 6) , desc1).join(); - //thread( AZStd::bind(&MfTest::g6, x, 1, 2, 3, 4, 5, 6) , desc1).join(); - //thread( AZStd::bind(&MfTest::g6, AZStd::ref(x), 1, 2, 3, 4, 5, 6) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f6, &x, 1, 2, 3, 4, 5, 6)).join(); + //thread( AZStd::bind(desc1, &MfTest::f6, AZStd::ref(x), 1, 2, 3, 4, 5, 6)).join(); + //thread( AZStd::bind(desc1, &MfTest::g6, &x, 1, 2, 3, 4, 5, 6)).join(); + //thread( AZStd::bind(desc1, &MfTest::g6, x, 1, 2, 3, 4, 5, 6)).join(); + //thread( AZStd::bind(desc1, &MfTest::g6, AZStd::ref(x), 1, 2, 3, 4, 5, 6)).join(); //// 7 - //thread( AZStd::bind(&MfTest::f7, &x, 1, 2, 3, 4, 5, 6, 7), desc1).join(); - //thread( AZStd::bind(&MfTest::f7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7), desc1).join(); - //thread( AZStd::bind(&MfTest::g7, &x, 1, 2, 3, 4, 5, 6, 7), desc1).join(); - //thread( AZStd::bind(&MfTest::g7, x, 1, 2, 3, 4, 5, 6, 7), desc1).join(); - //thread( AZStd::bind(&MfTest::g7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7), desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f7, &x, 1, 2, 3, 4, 5, 6, 7)).join(); + //thread( AZStd::bind(desc1, &MfTest::f7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7)).join(); + //thread( AZStd::bind(desc1, &MfTest::g7, &x, 1, 2, 3, 4, 5, 6, 7)).join(); + //thread( AZStd::bind(desc1, &MfTest::g7, x, 1, 2, 3, 4, 5, 6, 7)).join(); + //thread( AZStd::bind(desc1, &MfTest::g7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7)).join(); //// 8 - //thread( AZStd::bind(&MfTest::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join(); - //thread( AZStd::bind(&MfTest::f8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join(); - //thread( AZStd::bind(&MfTest::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join(); - //thread( AZStd::bind(&MfTest::g8, x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join(); - //thread( AZStd::bind(&MfTest::g8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8)).join(); + //thread( AZStd::bind(desc1, &MfTest::f8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8)).join(); + //thread( AZStd::bind(desc1, &MfTest::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8)).join(); + //thread( AZStd::bind(desc1, &MfTest::g8, x, 1, 2, 3, 4, 5, 6, 7, 8)).join(); + //thread( AZStd::bind(desc1, &MfTest::g8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8)).join(); AZ_TEST_ASSERT(x.m_hash == 1366); } diff --git a/Code/Framework/AzCore/Tests/Memory.cpp b/Code/Framework/AzCore/Tests/Memory.cpp index eb854050b6..5a483c1ed1 100644 --- a/Code/Framework/AzCore/Tests/Memory.cpp +++ b/Code/Framework/AzCore/Tests/Memory.cpp @@ -151,7 +151,7 @@ namespace UnitTest AZStd::thread m_threads[m_maxNumThreads]; for (unsigned int i = 0; i < m_maxNumThreads; ++i) { - m_threads[i] = AZStd::thread(AZStd::bind(&SystemAllocatorTest::ThreadFunc, this), &m_desc[i]); + m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&SystemAllocatorTest::ThreadFunc, this)); // give some time offset to the threads so we can test alloc and dealloc at the same time. //AZStd::this_thread::sleep_for(AZStd::chrono::microseconds(500)); } @@ -286,7 +286,7 @@ namespace UnitTest AZStd::thread m_threads[m_maxNumThreads]; for (unsigned int i = 0; i < m_maxNumThreads; ++i) { - m_threads[i] = AZStd::thread(AZStd::bind(&SystemAllocatorTest::ThreadFunc, this), &m_desc[i]); + m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&SystemAllocatorTest::ThreadFunc, this)); // give some time offset to the threads so we can test alloc and dealloc at the same time. AZStd::this_thread::sleep_for(AZStd::chrono::microseconds(500)); } @@ -724,7 +724,7 @@ namespace UnitTest AZStd::thread m_threads[m_maxNumThreads]; for (unsigned int i = 0; i < m_maxNumThreads; ++i) { - m_threads[i] = AZStd::thread(AZStd::bind(&ThreadPoolAllocatorTest::AllocDeallocFunc, this), &m_desc[i]); + m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&ThreadPoolAllocatorTest::AllocDeallocFunc, this)); } for (unsigned int i = 0; i < m_maxNumThreads; ++i) @@ -743,12 +743,12 @@ namespace UnitTest for (unsigned int i = m_maxNumThreads/2; i c_str()); if (cache) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h b/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h index f85fd273ce..e89d16ee5d 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h @@ -11,7 +11,9 @@ #include #include +#include #include +#include #include namespace AZ::IO @@ -71,6 +73,13 @@ namespace AZ::IO // multiple times FLAGS_DONT_COMPACT = 1 << 5, + // if this is set, validate header data when opening the archive + FLAGS_VALIDATE_HEADERS = 1 << 9, + + // if this is set, validate header data when opening the archive and validate CRCs when decompressing + // & reading files. + FLAGS_FULL_VALIDATE = 1 << 10, + // Disable a pak file without unloading it, this flag is used in combination with patches and multiplayer // to ensure that specific paks stay in the position(to keep the same priority) but being disabled // when running multiplayer @@ -128,6 +137,10 @@ namespace AZ::IO // Deletes all files and directories in the archive. virtual int RemoveAll() = 0; + // Summary: + // Lists all the files in the archive. + virtual int ListAllFiles(AZStd::vector& outFileEntries) = 0; + // Summary: // Finds the file; you don't have to close the returned handle. // Returns: diff --git a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp index 1e0f237df5..49a44b76fa 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp @@ -89,11 +89,51 @@ namespace AZ::IO return m_pCache->RemoveDir(fullPath); } + ////////////////////////////////////////////////////////////////////////// int NestedArchive::RemoveAll() { return m_pCache->RemoveAll(); } + ////////////////////////////////////////////////////////////////////////// + // Helper for 'ListAllFiles' to recursively traverse the FileEntryTree and gather all the files + void EnumerateFilesRecursive(AZ::IO::Path currentPath, ZipDir::FileEntryTree* currentTree, AZStd::vector& fileList) + { + // Drill down directories first... + for (auto dirIter = currentTree->GetDirBegin(); dirIter != currentTree->GetDirEnd(); ++dirIter) + { + if (ZipDir::FileEntryTree* subTree = currentTree->GetDirEntry(dirIter); + subTree != nullptr) + { + EnumerateFilesRecursive(currentPath / currentTree->GetDirName(dirIter), subTree, fileList); + } + } + + // Then enumerate the files in current directory... + for (auto fileIter = currentTree->GetFileBegin(); fileIter != currentTree->GetFileEnd(); ++fileIter) + { + fileList.emplace_back(currentPath / currentTree->GetFileName(fileIter)); + } + } + + ////////////////////////////////////////////////////////////////////////// + // lists all files in the archive + int NestedArchive::ListAllFiles(AZStd::vector& outFileEntries) + { + AZStd::vector filesInArchive; + + ZipDir::FileEntryTree* tree = m_pCache->GetRoot(); + if (!tree) + { + return ZipDir::ZD_ERROR_UNEXPECTED; + } + + EnumerateFilesRecursive(AZ::IO::Path{ AZ::IO::PosixPathSeparator }, tree, filesInArchive); + + AZStd::swap(outFileEntries, filesInArchive); + return ZipDir::ZD_ERROR_SUCCESS; + } + ////////////////////////////////////////////////////////////////////////// // Adds a new file to the zip or update an existing one // adds a directory (creates several nested directories if needed) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h index 34bbcdc201..59722703f2 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h @@ -39,7 +39,7 @@ namespace AZ::IO NestedArchive(IArchive* pArchive, AZStd::string_view strBindRoot, ZipDir::CachePtr pCache, uint32_t nFlags = 0); ~NestedArchive() override; - + auto GetRootFolderHandle() -> Handle override; // Adds a new file to the zip or update an existing one @@ -68,6 +68,9 @@ namespace AZ::IO // deletes all files from the archive int RemoveAll() override; + // lists all the files in the archive + int ListAllFiles(AZStd::vector& outFileEntries) override; + // finds the file; you don't have to close the returned handle Handle FindFile(AZStd::string_view szRelativePath) override; @@ -79,7 +82,6 @@ namespace AZ::IO // returns the full path to the archive file AZ::IO::PathView GetFullPath() const override; - ZipDir::Cache* GetCache(); uint32_t GetFlags() const override; bool SetFlags(uint32_t nFlagsToSet) override; @@ -87,12 +89,15 @@ namespace AZ::IO bool SetPackAccessible(bool bAccessible) override; + ZipDir::Cache* GetCache(); + protected: // returns the pointer to the relative file path to be passed // to the underlying Cache pointer. Uses the given buffer to construct the path. // returns nullptr if the file path is invalid AZ::IO::FixedMaxPathString AdjustPath(AZStd::string_view szRelativePath); + ZipDir::CachePtr m_pCache; // the binding root may be empty string - in this case, the absolute path binding won't work AZ::IO::Path m_strBindRoot; diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp index d17dbd0837..13d5b0f723 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp @@ -101,10 +101,11 @@ namespace AZ::IO::ZipDir FileEntry* operator -> () { return m_pFileEntry; } FileEntryTransactionAdd(Cache* pCache, AZStd::string_view szRelativePath) : m_pCache(pCache) + , m_szRelativePath(AZ::IO::PosixPathSeparator) , m_bCommitted(false) { // Update the cache string pool with the relative path to the file - auto pathIt = m_pCache->m_relativePathPool.emplace(AZ::IO::PathView(szRelativePath).LexicallyNormal()); + auto pathIt = m_pCache->m_relativePathPool.emplace(AZ::IO::PathView(szRelativePath, AZ::IO::PosixPathSeparator).LexicallyNormal()); m_szRelativePath = *pathIt.first; // this is the name of the directory - create it or find it m_pFileEntry = m_pCache->GetRoot()->Add(m_szRelativePath.Native()); @@ -740,6 +741,16 @@ namespace AZ::IO::ZipDir { return ZD_ERROR_CORRUPTED_DATA; } + if (pFileEntry->bCheckCRCNextRead) + { + pFileEntry->bCheckCRCNextRead = false; + uLong uCRC32 = AZ::Crc32((Bytef*)pUncompressed, nSizeUncompressed); + if (uCRC32 != pFileEntry->desc.lCRC32) + { + AZ_Warning("Archive", false, "ZD_ERROR_CRC32_CHECK: Uncompressed stream CRC32 check failed"); + return ZD_ERROR_CRC32_CHECK; + } + } } } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp index 5c5e93d441..d5bd4d2840 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp @@ -29,7 +29,7 @@ namespace AZ::IO::ZipDir // this sets the window size of the blocks of data read from the end of the file to find the Central Directory Record // since normally there are no static constexpr size_t CDRSearchWindowSize = 0x100; - CacheFactory::CacheFactory(InitMethodEnum nInitMethod, uint32_t nFlags) + CacheFactory::CacheFactory(InitMethod nInitMethod, uint32_t nFlags) { m_nCDREndPos = 0; m_bBuildFileEntryMap = false; // we only need it for validation/debugging @@ -448,7 +448,6 @@ namespace AZ::IO::ZipDir // builds up the m_mapFileEntries bool CacheFactory::BuildFileEntryMap() { - Seek(m_CDREnd.lCDROffset); if (m_CDREnd.lCDRSize == 0) @@ -530,14 +529,6 @@ namespace AZ::IO::ZipDir { // Add this file entry. char* str = reinterpret_cast(pFileName); - for (int i = 0; i < pFile->nFileNameLength; i++) - { - str[i] = std::tolower(str[i], std::locale()); - if (str[i] == AZ_WRONG_FILESYSTEM_SEPARATOR) - { - str[i] = AZ_CORRECT_FILESYSTEM_SEPARATOR; - } - } str[pFile->nFileNameLength] = 0; // Not standard!, may overwrite signature of the next memory record data in zip. AddFileEntry(str, pFile, extra); } @@ -574,11 +565,7 @@ namespace AZ::IO::ZipDir FileEntryBase fileEntry(*pFileHeader, extra); - // when using encrypted headers we should always initialize data offsets from CDR - if ((m_encryptedHeaders != ZipFile::HEADERS_NOT_ENCRYPTED || m_nInitMethod >= ZD_INIT_FULL) && pFileHeader->desc.lSizeCompressed) - { - InitDataOffset(fileEntry, pFileHeader); - } + InitDataOffset(fileEntry, pFileHeader); if (m_bBuildFileEntryMap) { @@ -606,142 +593,81 @@ namespace AZ::IO::ZipDir { Seek(pFileHeader->lLocalHeaderOffset); - // read the local file header and the name (for validation) into the buffer - AZStd::vectorpBuffer; - uint32_t nBufferLength = sizeof(ZipFile::LocalFileHeader) + pFileHeader->nFileNameLength; - pBuffer.resize(nBufferLength); - Read(&pBuffer[0], nBufferLength); + // Read only the LocalFileHeader w/ no additional bytes ('name' or 'extra' fields) + AZStd::vector buffer; + uint32_t bufferLen = sizeof(ZipFile::LocalFileHeader); + buffer.resize_no_construct(bufferLen); + Read(buffer.data(), bufferLen); - // validate the local file header (compare with the CDR file header - they should contain basically the same information) - const auto* pLocalFileHeader = reinterpret_cast(&pBuffer[0]); - if (pFileHeader->desc != pLocalFileHeader->desc - || pFileHeader->nMethod != pLocalFileHeader->nMethod - || pFileHeader->nFileNameLength != pLocalFileHeader->nFileNameLength - // for a tough validation, we can compare the timestamps of the local and central directory entries - // but we won't do that for backward compatibility with ZipDir - //|| pFileHeader->nLastModDate != pLocalFileHeader->nLastModDate - //|| pFileHeader->nLastModTime != pLocalFileHeader->nLastModTime - ) + const auto* localFileHeader = reinterpret_cast(buffer.data()); + + // set the correct file data offset... + fileEntry.nFileDataOffset = pFileHeader->lLocalHeaderOffset + sizeof(ZipFile::LocalFileHeader) + + localFileHeader->nFileNameLength + localFileHeader->nExtraFieldLength; + + fileEntry.nEOFOffset = fileEntry.nFileDataOffset + fileEntry.desc.lSizeCompressed; + + if (m_nInitMethod != ZipDir::InitMethod::Default) { - AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:" - " The local file header descriptor doesn't match the basic parameters declared in the global file header in the file." - " The archive content is misconsistent and may be damaged. Please try to repair the archive"); - return; + if (m_nInitMethod == ZipDir::InitMethod::FullValidation) + { + // Mark the FileEntry to check CRC when the next read occurs + fileEntry.bCheckCRCNextRead = true; + } + + // Timestamps + if (pFileHeader->nLastModDate != localFileHeader->nLastModDate + || pFileHeader->nLastModTime != localFileHeader->nLastModTime) + { + AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n" + " The local file header's modification timestamps don't match that of the global file header in the archive." + " The archive timestamps are inconsistent and may be damaged. Check the archive file.", m_szFilename.c_str()); + // don't return here, it may be ok. + } + + // Validate data + if (pFileHeader->desc != localFileHeader->desc // this checks CRCs and compressed/uncompressed sizes + || pFileHeader->nMethod != localFileHeader->nMethod + || pFileHeader->nFileNameLength != localFileHeader->nFileNameLength) + { + AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n" + " The local file header descriptor doesn't match basic parameters declared in the global file header in the file." + " The archive content is inconsistent and may be damaged. Please try to repair the archive.", m_szFilename.c_str()); + // return here because further checks aren't worse than this. + return; + } + + // Read extra data + uint32_t extraDataLen = localFileHeader->nFileNameLength + localFileHeader->nExtraFieldLength; + buffer.resize_no_construct(buffer.size() + extraDataLen); + Read(buffer.data() + buffer.size(), extraDataLen); + + // Compare local file name with the CDR file name, they should match + AZStd::string_view zipFileName{ buffer.data() + sizeof(ZipFile::LocalFileHeader), localFileHeader->nFileNameLength }; + AZStd::string_view cdrFileName{ reinterpret_cast(pFileHeader + 1), pFileHeader->nFileNameLength }; + if (zipFileName != cdrFileName) + { + AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n" + " The file name in the local file header doesn't match the name in the global file header." + " The archive content is inconsisten with the directory. Please check the archive.", m_szFilename.c_str()); + } + + // CDR and local "extra field" lengths may be different, should we compare them if they are equal? + + // make sure it's the same file and the fileEntry structure is properly initialized + AZ_Assert(fileEntry.nFileHeaderOffset == pFileHeader->lLocalHeaderOffset, + "The file entry header offset doesn't match the file header local offst (%s)", m_szFilename.c_str()); + + if (fileEntry.nFileDataOffset >= m_nCDREndPos) + { + AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n" + " The global file header declares the file which crosses the boundaries of the archive." + " The archive is either corrupted or truncated, please try to repair it", m_szFilename.c_str()); + } + + // End Validation } - - // now compare the local file name with the one recorded in CDR: they must match. - auto CompareNoCase = [](const char lhs, const char rhs) { return std::tolower(lhs, std::locale()) == std::tolower(rhs, std::locale()); }; - auto zipFileDataBegin = pBuffer.begin() + sizeof(ZipFile::LocalFileHeader); - auto zipFileDataEnd = zipFileDataBegin + pFileHeader->nFileNameLength; - if (!AZStd::equal(zipFileDataBegin, zipFileDataEnd, reinterpret_cast(pFileHeader + 1), CompareNoCase)) - { - // either file name, or the extra field do not match - AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:" - " The local file header contains file name which does not match the file name of the global file header." - " The archive content is misconsistent with its directory. Please repair the archive"); - return; - } - - fileEntry.nFileDataOffset = pFileHeader->lLocalHeaderOffset + sizeof(ZipFile::LocalFileHeader) + pLocalFileHeader->nFileNameLength + pLocalFileHeader->nExtraFieldLength; } - - // make sure it's the same file and the fileEntry structure is properly initialized - AZ_Assert(fileEntry.nFileHeaderOffset == pFileHeader->lLocalHeaderOffset, "The file entry header offset doesn't match the file header local offst"); - - fileEntry.nEOFOffset = fileEntry.nFileDataOffset + fileEntry.desc.lSizeCompressed; - - if (fileEntry.nFileDataOffset >= m_nCDREndPos) - { - AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:" - " The global file header declares the file which crosses the boundaries of the archive." - " The archive is either corrupted or truncated, please try to repair it"); - return; - } - - if (m_nInitMethod >= ZD_INIT_VALIDATE) - { - Validate(fileEntry); - } - } - - ////////////////////////////////////////////////////////////////////////// - // reads the file pointed by the given header and entry (they must be coherent) - // and decompresses it; then calculates and validates its CRC32 - void CacheFactory::Validate(const FileEntryBase& fileEntry) - { - AZStd::vector pBuffer; - // validate the file contents - // allocate memory for both the compressed data and uncompressed data - pBuffer.resize(fileEntry.desc.lSizeCompressed + fileEntry.desc.lSizeUncompressed); - char* pUncompressed = &pBuffer[fileEntry.desc.lSizeCompressed]; - char* pCompressed = &pBuffer[0]; - - AZ_Assert(fileEntry.nFileDataOffset != FileEntry::INVALID_DATA_OFFSET, "File entry has invalid data offset of %" PRIx32, FileEntry::INVALID_DATA_OFFSET); - Seek(fileEntry.nFileDataOffset); - - Read(pCompressed, fileEntry.desc.lSizeCompressed); - - size_t nDestSize = fileEntry.desc.lSizeUncompressed; - int nError = Z_OK; - if (fileEntry.nMethod) - { - nError = ZipRawUncompress(pUncompressed, &nDestSize, pCompressed, fileEntry.desc.lSizeCompressed); - } - else - { - AZ_Assert(fileEntry.desc.lSizeCompressed == fileEntry.desc.lSizeUncompressed, "Uncompressed file does not have the same commpressed %u and uncompressed file sizes %u", - fileEntry.desc.lSizeCompressed, fileEntry.desc.lSizeUncompressed); - memcpy(pUncompressed, pCompressed, fileEntry.desc.lSizeUncompressed); - } - switch (nError) - { - case Z_OK: - break; - case Z_MEM_ERROR: - AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_NO_MEMORY: ZLib reported out-of-memory error"); - return; - case Z_BUF_ERROR: - AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_CORRUPTED_DATA: ZLib reported compressed stream buffer error"); - return; - case Z_DATA_ERROR: - AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_CORRUPTED_DATA: ZLib reported compressed stream data error"); - return; - default: - AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_FAILED: ZLib reported an unexpected unknown error"); - return; - } - - if (nDestSize != fileEntry.desc.lSizeUncompressed) - { - AZ_Warning("Archive", false, "ZD_ERROR_CORRUPTED_DATA: Uncompressed stream doesn't match the size of uncompressed file stored in the archive file headers"); - return; - } - - uLong uCRC32 = AZ::Crc32((Bytef*)pUncompressed, nDestSize); - if (uCRC32 != fileEntry.desc.lCRC32) - { - AZ_Warning("Archive", false, "ZD_ERROR_CRC32_CHECK: Uncompressed stream CRC32 check failed"); - return; - } - } - - - ////////////////////////////////////////////////////////////////////////// - // extracts the file path from the file header with subsequent information - // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not) - // it's the responsibility of the caller to ensure that the file name is in readable valid memory - char* CacheFactory::GetFilePath(const char* pFileName, uint16_t nFileNameLength) - { - static char strResult[AZ_MAX_PATH_LEN]; - AZ_Assert(nFileNameLength < AZ_MAX_PATH_LEN, "Only filenames shorter than %zu can be copied from filename parameter", AZ_MAX_PATH_LEN); - memcpy(strResult, pFileName, nFileNameLength); - strResult[nFileNameLength] = 0; - for (int i = 0; i < nFileNameLength; i++) - { - strResult[i] = std::tolower(strResult[i], std::locale{}); - } - - return strResult; } // seeks in the file relative to the starting position diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h index c31d4d7dfd..1612829f13 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h @@ -39,7 +39,7 @@ namespace AZ::IO::ZipDir // initializes the internal structures // nFlags can have FLAGS_READ_ONLY flag, in this case the object will be opened only for reading - CacheFactory(InitMethodEnum nInitMethod, uint32_t nFlags = 0); + CacheFactory(InitMethod nInitMethod, uint32_t nFlags = 0); ~CacheFactory(); // the new function creates a new cache @@ -66,28 +66,6 @@ namespace AZ::IO::ZipDir // This function can actually modify strFilePath variable, make sure you use a copy of the real path. void AddFileEntry(char* strFilePath, const ZipFile::CDRFileHeader* pFileHeader, const SExtraZipFileData& extra);// throw (ErrorEnum); - // extracts the file path from the file header with subsequent information - // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not) - // it's the responsibility of the caller to ensure that the file name is in readable valid memory - char* GetFilePath(const ZipFile::CDRFileHeader* pFileHeader) - { - return GetFilePath((const char*)(pFileHeader + 1), pFileHeader->nFileNameLength); - } - // extracts the file path from the file header with subsequent information - // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not) - // it's the responsibility of the caller to ensure that the file name is in readable valid memory - char* GetFilePath(const ZipFile::LocalFileHeader* pFileHeader) - { - return GetFilePath((const char*)(pFileHeader + 1), pFileHeader->nFileNameLength); - } - // extracts the file path from the file header with subsequent information - // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not) - // it's the responsibility of the caller to ensure that the file name is in readable valid memory - char* GetFilePath(const char* pFileName, uint16_t nFileNameLength); - - // validates (if the init method has the corresponding value) the given file/header - void Validate(const FileEntryBase& fileEntry); - // initializes the actual data offset in the file in the fileEntry structure // searches to the local file header, reads it and calculates the actual offset in the file void InitDataOffset(FileEntryBase& fileEntry, const ZipFile::CDRFileHeader* pFileHeader); @@ -104,7 +82,7 @@ namespace AZ::IO::ZipDir AZStd::string m_szFilename; CZipFile m_fileExt; - InitMethodEnum m_nInitMethod; + InitMethod m_nInitMethod; uint32_t m_nFlags; ZipFile::CDREnd m_CDREnd; @@ -129,7 +107,7 @@ namespace AZ::IO::ZipDir ZipFile::CryCustomEncryptionHeader m_headerEncryption; ZipFile::CrySignedCDRHeader m_headerSignature; ZipFile::CryCustomExtendedHeader m_headerExtended; - }; + } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp index 729f394b9d..ab9c356d7f 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp @@ -68,14 +68,14 @@ namespace AZ::IO::ZipDir { for (FileEntryTree::SubdirMap::iterator it = pTree->GetDirBegin(); it != pTree->GetDirEnd(); ++it) { - AddAllFiles(it->second.get(), (AZ::IO::Path(strRoot) / it->first).Native()); + AddAllFiles(it->second.get(), (AZ::IO::Path(strRoot, AZ::IO::PosixPathSeparator) / it->first).Native()); } for (FileEntryTree::FileMap::iterator it = pTree->GetFileBegin(); it != pTree->GetFileEnd(); ++it) { FileRecord rec; rec.pFileEntryBase = pTree->GetFileEntry(it); - rec.strPath = (AZ::IO::Path(strRoot) / it->first).Native(); + rec.strPath = (AZ::IO::Path(strRoot, AZ::IO::PosixPathSeparator) / it->first).Native(); push_back(rec); } } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h index 9295a7dd95..c890d498e4 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h @@ -119,19 +119,28 @@ namespace AZ::IO::ZipDir const char* m_szDescription; }; +#if defined(_RELEASE) + inline static constexpr bool IsReleaseConfig{ true }; +#else + inline static constexpr bool IsReleaseConfig{}; +#endif // _RELEASE + // possible initialization methods - enum InitMethodEnum + enum class InitMethod { - // initialize as fast as possible, with minimal validation - ZD_INIT_FAST, - // after initialization, scan through all file headers, precache the actual file data offset values and validate the headers - ZD_INIT_FULL, - // scan all file headers and try to decompress the data, searching for corrupted files - ZD_INIT_VALIDATE_IN_MEMORY, - // store archive in memory - ZD_INIT_VALIDATE, - // maximum level of validation, checks for integrity of the archive - ZD_INIT_VALIDATE_MAX = ZD_INIT_VALIDATE + // initializes without any sort of extra validation steps + Default, + + // initializes with extra validation steps + // not available in RELEASE + // will check CDR and local headers data match + ValidateHeaders, + + // initializes with extra validation steps + // not available in RELEASE + // will check CDR and local headers data match + // will check file data CRC matches (when file is read) + FullValidation, }; // Uncompresses raw (without wrapping) data that is compressed with method 8 (deflated) in the Zip file @@ -184,7 +193,11 @@ namespace AZ::IO::ZipDir // the offset to the start of the next file's header - this // can be used to calculate the available space in zip file uint32_t nEOFOffset{}; + + // whether to check the CRC upon the next data read + bool bCheckCRCNextRead{}; }; + // this is the record about the file in the Zip file. struct FileEntry : FileEntryBase diff --git a/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp b/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp index 2e1cde443c..74b92a5681 100644 --- a/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp +++ b/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp @@ -593,7 +593,7 @@ namespace AzFramework DebugMessage("StartThread: Starting %s", thread.m_desc.m_name); thread.m_join = false; - thread.m_thread = AZStd::thread(thread.m_main, &thread.m_desc); + thread.m_thread = AZStd::thread(thread.m_desc, thread.m_main); } void AssetProcessorConnection::JoinThread(ThreadState& thread, AZStd::condition_variable* wakeUpCondition /* = nullptr */) diff --git a/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp b/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp index 1c26cbc744..8e6bacda2b 100644 --- a/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp @@ -319,7 +319,7 @@ namespace AzFramework AZStd::thread_desc td; td.m_name = "TargetManager Thread"; td.m_cpuId = AFFINITY_MASK_USERTHREADS; - m_threadHandle = AZStd::thread(AZStd::bind(&TargetManagementComponent::TickThread, this), &td); + m_threadHandle = AZStd::thread(td, AZStd::bind(&TargetManagementComponent::TickThread, this)); } void TargetManagementComponent::Deactivate() diff --git a/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp b/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp index c85d15ae45..565b37202a 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp @@ -26,27 +26,29 @@ namespace AzNetworking { m_running = true; m_joinable = true; - m_thread = AZStd::thread([this]() - { - OnStart(); - while (m_running) + m_thread = AZStd::thread( + m_threadDesc, + [this]() { - const AZ::TimeMs startTimeMs = AZ::GetElapsedTimeMs(); - OnUpdate(m_updateRate); - const AZ::TimeMs updateTimeMs = AZ::GetElapsedTimeMs() - startTimeMs; + OnStart(); + while (m_running) + { + const AZ::TimeMs startTimeMs = AZ::GetElapsedTimeMs(); + OnUpdate(m_updateRate); + const AZ::TimeMs updateTimeMs = AZ::GetElapsedTimeMs() - startTimeMs; - if (m_updateRate > updateTimeMs) - { - AZStd::chrono::milliseconds sleepTimeMs(static_cast(m_updateRate - updateTimeMs)); - AZStd::this_thread::sleep_for(sleepTimeMs); + if (m_updateRate > updateTimeMs) + { + AZStd::chrono::milliseconds sleepTimeMs(static_cast(m_updateRate - updateTimeMs)); + AZStd::this_thread::sleep_for(sleepTimeMs); + } + else if (m_updateRate < updateTimeMs) + { + AZLOG(NET_TimedThread, "TimedThread bled %d ms", aznumeric_cast(updateTimeMs - m_updateRate)); + } } - else if (m_updateRate < updateTimeMs) - { - AZLOG(NET_TimedThread, "TimedThread bled %d ms", aznumeric_cast(updateTimeMs - m_updateRate)); - } - } - OnStop(); - }, &m_threadDesc); + OnStop(); + }); } void TimedThread::Stop() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveAPI.h index fa8c2c14ff..11c4c85722 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveAPI.h @@ -12,95 +12,84 @@ #include #include #include +#include namespace AzToolsFramework { - // use bind if you need additional context. - // Parameters: - // bool - If the archive command was successful or not. - typedef AZStd::function ArchiveResponseCallback; - // bool - If the archive command was successful or not. - // AZStd::string - The console output from the command. - typedef AZStd::function ArchiveResponseOutputCallback; - - //! ArchiveCommands //! This bus handles messages relating to archive commands //! archive commands are ASYNCHRONOUS //! archive formats officially supported are .zip - //! do not block the main thread waiting for a response, it is not okay - //! you will not get a message delivered unless you tick the tickbus anyway! class ArchiveCommands : public AZ::EBusTraits { public: - - using Bus = AZ::EBus; - + // EBus Traits static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; typedef AZStd::recursive_mutex MutexType; static const bool LocklessDispatch = true; - virtual ~ArchiveCommands() {} - //! Start an async task to extract an archive to the target directory - //! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task. - //! Multiple tasks can be associated with the same handle - virtual void ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) = 0; - virtual void ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; - // Maintaining backwards API compatibility - ExtractArchiveBlocking below passes in extractWithRoot as an option - virtual void ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; + virtual ~ArchiveCommands() = default; - //! Start a sync task to extract an archive to the target directory - //! If you do not want to extract the root folder then set extractWithRootDirectory to false. - virtual bool ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) = 0; + //! Create an archive of the target directory (all files and subdirectories) + //! @param archivePath The path of the archive to create + //! @dirToArchive The directory to be added to the archive + //! @return Future (bool) which can obtain the success value of the operation + [[nodiscard]] virtual std::future CreateArchive( + const AZStd::string& archivePath, + const AZStd::string& dirToArchive) = 0; - //! Extract a single file asynchronously from the archive to the destination. - //! Uses cwd if destinationPath empty. overWrite = true for overwrite existing files, false for skipExisting - //! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task. - //! Multiple tasks can be associated with the same handle - virtual void ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; + //! Extract an archive to the target directory + //! @param archivePath The path of the archive to extract + //! @param destinationPath The directory where files will be extracted to + //! @return Future (bool) which can obtain the success value of the operation + [[nodiscard]] virtual std::future ExtractArchive( + const AZStd::string& archivePath, + const AZStd::string& destinationPath) = 0; - //! Extract a single file from the archive to the destination and block until finished. - //! Uses cwd if destinationPath empty. overWrite = true for overwrite existing files, false for skipExisting - virtual bool ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) = 0; + //! Extract a single file from the archive to the destination + //! Destination path should not be empty + //! @param archivePath The path of the archive to extract from + //! @param fileInArchive A path to a file, relative to root of archive + //! @param destinationPath The directory where file will be extracted to + //! @return Future (bool) which can obtain the success value of the operation + [[nodiscard]] virtual std::future ExtractFile( + const AZStd::string& archivePath, + const AZStd::string& fileInArchive, + const AZStd::string& destinationPath) = 0; - //! Start an async task to create an archive of the target directory (recursively) - //! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task. - //! Multiple tasks can be associated with the same handle. - virtual void CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; + //! Retrieve the list of files contained in an archive (all files and subdirectories) + //! @param archivePath The path of the archive to list + //! @param outFileEntries An out parameter that will contain the file paths found + //! @return True if successful, false otherwise + virtual bool ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& outFileEntries) = 0; - //! Start a sync task to create an archive of the target directory (recursively) - virtual bool CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) = 0; - - //! Start an async task to retrieve the list of files and their relative paths within an archive (recursively) - //! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task. - //! Multiple tasks can be associated with the same handle. - virtual void ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& fileEntries, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; + //! Add a file to an archive + //! The archive might not exist yet + //! The file path relative to the working directory will be replicated in the archive + //! @param archivePath The path of the archive to add to + //! @param workingDirectory A directory that will be the starting path of the file to be added + //! @param fileToAdd A path to the file relative to the working directory + //! @return Future (bool) which can obtain the success value of the operation + [[nodiscard]] virtual std::future AddFileToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& fileToAdd) = 0; - //! Start a sync task to retrieve the list of files and their relative paths within an archive (recursively) - virtual bool ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector& fileEntries) = 0; - - //! Start an async task to add a file to a preexisting archive. - //! fileToAdd must be a relative path to the file from the working directory. The path to the file from the root of the archive will be the same as the relative path to the file on disk. - //! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task. - //! Multiple tasks can be associated with the same handle. - virtual void AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; - - //! Start a sync task to add a file to a preexisting archive. - //! fileToAdd must be a relative path to the file from the working directory. The path to the file from the root of the archive will be the same as the relative path to the file on disk. - virtual bool AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd) = 0; - - //! Start an async task to add files to a archive. - //! File paths inside the list file must either be a relative path from the working directory or an absolute path. - virtual void AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; - - //! Start a sync task to add files to an archive. - //! File paths inside the list file must either be a relative path from the working directory or an absolute path. - virtual bool AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) = 0; - - //! Cancels tasks associtated with the given handle. Blocks until all tasks are cancelled. - virtual void CancelTasks(AZ::Uuid taskHandle) = 0; + //! Add files to an archive provided from a file listing + //! The archive might not exist yet + //! File paths in the file list should be relative to root of the archive + //! @param archivePath The path of the archive to add to + //! @param workingDirectory A directory that will be the starting path of the list of files to add + //! @param listFilePath Full path to a text file that contains the list of files to add + //! @return Future (bool) which can obtain the success value of the operation + [[nodiscard]] virtual std::future AddFilesToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& listFilePath) = 0; }; + using ArchiveCommandsBus = AZ::EBus; + }; // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp index 5004108132..8e07794c33 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp @@ -12,118 +12,98 @@ #include #include -#include - +#include +#include #include #include #include + namespace AzToolsFramework { - // Forward declare platform specific functions - namespace Platform + constexpr const char s_traceName[] = "ArchiveComponent"; + constexpr AZ::u32 s_compressionMethod = AZ::IO::INestedArchive::METHOD_DEFLATE; + constexpr AZ::s32 s_compressionLevel = AZ::IO::INestedArchive::LEVEL_NORMAL; + constexpr CompressionCodec::Codec s_compressionCodec = CompressionCodec::Codec::ZLIB; + + namespace ArchiveUtils { - AZStd::string GetZipExePath(); - AZStd::string GetUnzipExePath(); - - AZStd::string GetCreateArchiveCommand(const AZStd::string& archivePath, const AZStd::string& dirToArchive); - AZStd::string GetExtractArchiveCommand(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot); - AZStd::string GetAddFileToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& file); - AZStd::string GetAddFilesToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& listFilePath); - AZStd::string GetExtractFileCommand(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite); - AZStd::string GetListFilesInArchiveCommand(const AZStd::string& archivePath); - void ParseConsoleOutputFromListFilesInArchive(const AZStd::string& consoleOutput, AZStd::vector& fileEntries); - } - - const char s_traceName[] = "ArchiveComponent"; - const unsigned int g_sleepDuration = 1; - - // Echoes all results of stdout and stderr to console and never blocks - class ConsoleEchoCommunicator - { - public: - ConsoleEchoCommunicator(AzFramework::ProcessCommunicator* communicator) - : m_communicator(communicator) + // Read a file's contents into a provided buffer. + // Does not add a zero byte at the end of the buffer. + // returns true if read was successful, false otherwise. + bool ReadFile(const AZ::IO::Path& filePath, AZ::IO::OpenMode openMode, AZStd::vector& outBuffer) { - } - - ~ConsoleEchoCommunicator() - { - } - - // Call this periodically to drain the buffers - void Pump() - { - if (m_communicator->IsValid()) + auto fileIO = AZ::IO::FileIOBase::GetDirectInstance(); + if (!fileIO) { - AZ::u32 readBufferSize = 0; - AZStd::string readBuffer; - // Don't call readOutput unless there is output or else it will block... - readBufferSize = m_communicator->PeekOutput(); - if (readBufferSize) - { - readBuffer.resize_no_construct(readBufferSize + 1); - readBuffer[readBufferSize] = '\0'; - m_communicator->ReadOutput(readBuffer.data(), readBufferSize); - EchoBuffer(readBuffer); - } - readBufferSize = m_communicator->PeekError(); - if (readBufferSize) - { - readBuffer.resize_no_construct(readBufferSize + 1); - readBuffer[readBufferSize] = '\0'; - m_communicator->ReadError(readBuffer.data(), readBufferSize); - EchoBuffer(readBuffer); - } + return false; } - } - private: - void EchoBuffer(const AZStd::string& buffer) - { - size_t startIndex = 0; - size_t endIndex = 0; - const size_t bufferSize = buffer.size(); - for (size_t i = 0; i < bufferSize; ++i) + bool success = false; + AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; + if (fileIO->Open(filePath.c_str(), openMode, fileHandle)) { - if (buffer[i] == '\n' || buffer[i] == '\0') + AZ::u64 fileSize = 0; + if (fileIO->Size(fileHandle, fileSize) && fileSize != 0) { - endIndex = i; - bool isEmptyMessage = (endIndex - startIndex == 1) && (buffer[startIndex] == '\r'); - if (!isEmptyMessage) + outBuffer.resize_no_construct(fileSize); + + AZ::u64 bytesRead = 0; + if (fileIO->Read(fileHandle, outBuffer.data(), fileSize, true, &bytesRead)) { - AZ_Printf(s_traceName, "%s", buffer.substr(startIndex, endIndex - startIndex).c_str()); + success = (fileSize == bytesRead); } - startIndex = endIndex + 1; } + + fileIO->Close(fileHandle); + } + + return success; + } + + // Reads a text file that contains a list of file paths. + // Tokenize the file by lines. + // Calls the lineVisitor function for each line of the file. + void ProcessFileList(const AZ::IO::Path& filePath, AZStd::function lineVisitor) + { + AZStd::vector fileBuffer; + if (ReadFile(filePath, AZ::IO::OpenMode::ModeText | AZ::IO::OpenMode::ModeRead, fileBuffer)) + { + AZ::StringFunc::TokenizeVisitor(AZStd::string_view{ fileBuffer.data(), fileBuffer.size() }, lineVisitor, "\n"); } } - AzFramework::ProcessCommunicator* m_communicator = nullptr; - }; + } // namespace ArchiveUtils void ArchiveComponent::Activate() { - m_zipExePath = Platform::GetZipExePath(); - m_unzipExePath = Platform::GetUnzipExePath(); + m_fileIO = AZ::IO::FileIOBase::GetDirectInstance(); + if (m_fileIO == nullptr) + { + AZ_Error(s_traceName, false, "Failed to create a LocalFileIO instance!"); + } - ArchiveCommands::Bus::Handler::BusConnect(); + m_archive = AZ::Interface::Get(); + if (m_archive == nullptr) + { + AZ_Error(s_traceName, false, "Failed to get IArchive interface!"); + } + + ArchiveCommandsBus::Handler::BusConnect(); } void ArchiveComponent::Deactivate() { - ArchiveCommands::Bus::Handler::BusDisconnect(); + ArchiveCommandsBus::Handler::BusDisconnect(); - AZStd::unique_lock lock(m_threadControlMutex); - for (auto pair : m_threadInfoMap) + m_fileIO = nullptr; + m_archive = nullptr; + + for (AZStd::thread& t : m_threads) { - ThreadInfo& info = pair.second; - info.shouldStop = true; - m_cv.wait(lock, [&info]() { - return info.threads.size() == 0; - }); + t.join(); } - m_threadInfoMap.clear(); + m_threads = {}; } void ArchiveComponent::Reflect(AZ::ReflectContext * context) @@ -132,7 +112,7 @@ namespace AzToolsFramework { serializeContext->Class() ->Version(2) - ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector({ AZ_CRC("AssetBuilder", 0xc739c7d7) })) + ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector({ AZ_CRC_CE("AssetBuilder") })) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -141,320 +121,480 @@ namespace AzToolsFramework "Archive", "Handles creation and extraction of zip archives.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "Editor") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) ; } } } - void ArchiveComponent::CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) + std::future ArchiveComponent::CreateArchive( + const AZStd::string& archivePath, + const AZStd::string& dirToArchive) { - AZStd::string commandLineArgs = AZStd::string::format(R"(a -tzip -mx=1 "%s" -r "%s\*")", archivePath.c_str(), dirToArchive.c_str()); - LaunchZipExe(m_zipExePath, commandLineArgs, respCallback, taskHandle); - } - - bool ArchiveComponent::CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) - { - bool success = false; - auto createArchiveCallback = [&success](bool result, AZStd::string consoleOutput) { - success = result; - }; - - AZStd::string commandLineArgs = Platform::GetCreateArchiveCommand(archivePath, dirToArchive); - - if (commandLineArgs.empty()) + if (!CheckParamsForCreate(archivePath, dirToArchive)) { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return false; + std::promise p; + p.set_value(false); + return p.get_future(); } - LaunchZipExe(m_zipExePath, commandLineArgs, createArchiveCallback, AZ::Uuid::CreateNull(), dirToArchive, false); - return success; - } - - void ArchiveComponent::ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) - { - ArchiveResponseOutputCallback responseHandler = [respCallback](bool result, AZStd::string /*outputStr*/) { respCallback(result); }; - ExtractArchiveOutput(archivePath, destinationPath, taskHandle, responseHandler); - } - - void ArchiveComponent::ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = Platform::GetExtractArchiveCommand(archivePath, destinationPath, true); - - if (commandLineArgs.empty()) + auto FnCreateArchive = [this, archivePath, dirToArchive](std::promise&& p) -> void { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return; - } - - LaunchZipExe(m_unzipExePath, commandLineArgs, respCallback, taskHandle); - } - - void ArchiveComponent::ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = Platform::GetExtractArchiveCommand(archivePath, destinationPath, false); - - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return; - } - - LaunchZipExe(m_unzipExePath, commandLineArgs, respCallback, taskHandle); - } - - void ArchiveComponent::ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = AzToolsFramework::Platform::GetExtractFileCommand(archivePath, fileInArchive, destinationPath, overWrite); - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return; - } - LaunchZipExe(m_unzipExePath, commandLineArgs, respCallback, taskHandle); - } - - bool ArchiveComponent::ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) - { - AZStd::string commandLineArgs = AzToolsFramework::Platform::GetExtractFileCommand(archivePath, fileInArchive, destinationPath, overWrite); - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return false; - } - - bool success = false; - auto createArchiveCallback = [&success](bool result, AZStd::string consoleOutput) { - success = result; - }; - LaunchZipExe(m_unzipExePath, commandLineArgs, createArchiveCallback); - return success; - } - - void ArchiveComponent::ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& fileEntries, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = Platform::GetListFilesInArchiveCommand(archivePath); - - auto parseOutput = [respCallback, &fileEntries](bool exitCode, AZStd::string consoleOutput) - { - Platform::ParseConsoleOutputFromListFilesInArchive(consoleOutput, fileEntries); - AZ::TickBus::QueueFunction(respCallback, exitCode, AZStd::move(consoleOutput)); - }; - LaunchZipExe(m_unzipExePath, commandLineArgs, parseOutput, taskHandle, "", true); - } - - bool ArchiveComponent::ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector& fileEntries) - { - AZStd::string listOutput; - AZStd::string commandLineArgs = Platform::GetListFilesInArchiveCommand(archivePath.c_str()); - bool success = false; - - auto parseOutput = [&success, &fileEntries](bool result, AZStd::string consoleOutput) - { - Platform::ParseConsoleOutputFromListFilesInArchive(consoleOutput, fileEntries); - success = result; - }; - LaunchZipExe(m_unzipExePath, commandLineArgs, parseOutput, AZ::Uuid::CreateNull(), "", true); - return success; - } - - void ArchiveComponent::AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = Platform::GetAddFileToArchiveCommand(archivePath, fileToAdd); - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return; - } - - LaunchZipExe(m_zipExePath, commandLineArgs, respCallback, taskHandle, workingDirectory); - } - - bool ArchiveComponent::AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd) - { - AZStd::string commandLineArgs = Platform::GetAddFileToArchiveCommand(archivePath, fileToAdd); - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return false; - } - bool success = false; - auto addFileToArchiveCallback = [&success](bool result, AZStd::string consoleOutput) { - success = result; - }; - - LaunchZipExe(m_zipExePath, commandLineArgs, addFileToArchiveCallback, AZ::Uuid::CreateNull(), workingDirectory); - return success; - } - - bool ArchiveComponent::AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) - { - bool success = false; - - auto addFileToArchiveCallback = [&success](bool result, AZStd::string consoleOutput) { - success = result; - }; - - AZStd::string commandLineArgs = Platform::GetAddFilesToArchiveCommand(archivePath.c_str(), listFilePath.c_str()); - - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return false; - } - LaunchZipExe(m_zipExePath, commandLineArgs, addFileToArchiveCallback, AZ::Uuid::CreateNull(), workingDirectory); - return success; - } - - void ArchiveComponent::AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = Platform::GetAddFilesToArchiveCommand(archivePath, listFilePath); - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return; - } - - LaunchZipExe(m_zipExePath, commandLineArgs, respCallback, taskHandle, workingDirectory); - } - - - bool ArchiveComponent::ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) - { - AZStd::string commandLineArgs = Platform::GetExtractArchiveCommand(archivePath, destinationPath, extractWithRootDirectory); - - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return false; - } - - bool success = false; - auto extractArchiveCallback = [&success](bool result, AZStd::string consoleOutput) { - success = result; - }; - - LaunchZipExe(m_unzipExePath, commandLineArgs, extractArchiveCallback); - return success; - } - - void ArchiveComponent::CancelTasks(AZ::Uuid taskHandle) - { - AZStd::unique_lock lock(m_threadControlMutex); - - auto it = m_threadInfoMap.find(taskHandle); - if (it == m_threadInfoMap.end()) - { - return; - } - - ThreadInfo& info = it->second; - info.shouldStop = true; - m_cv.wait(lock, [&info]() { - return info.threads.size() == 0; - }); - m_threadInfoMap.erase(it); - } - - void ArchiveComponent::LaunchZipExe(const AZStd::string& exePath, const AZStd::string& commandLineArgs, const ArchiveResponseOutputCallback& respCallback, AZ::Uuid taskHandle, const AZStd::string& workingDir, bool captureOutput) - { - auto sevenZJob = [=]() - { - if (!taskHandle.IsNull()) + auto archive = m_archive->OpenArchive(archivePath, {}, AZ::IO::INestedArchive::FLAGS_CREATE_NEW); + if (!archive) { - AZStd::unique_lock lock(m_threadControlMutex); - m_threadInfoMap[taskHandle].threads.insert(AZStd::this_thread::get_id()); - m_cv.notify_all(); + AZ_Error(s_traceName, false, "Failed to create archive file '%s'", archivePath.c_str()); + p.set_value(false); + return; } - AzFramework::ProcessLauncher::ProcessLaunchInfo info; - info.m_commandlineParameters = exePath + " " + commandLineArgs; - - info.m_showWindow = false; - if (!workingDir.empty()) + auto foundFiles = AzFramework::FileFunc::FindFilesInPath(dirToArchive, "*", true); + if (!foundFiles.IsSuccess()) { - info.m_workingDirectory = workingDir; + AZ_Error(s_traceName, false, "Failed to find file listing under directory '%d'", dirToArchive.c_str()); + p.set_value(false); + return; } - AZStd::unique_ptr watcher(AzFramework::ProcessWatcher::LaunchProcess(info, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT)); - AZStd::string consoleOutput; - AZ::u32 exitCode = static_cast(SevenZipExitCode::UserStoppedProcess); - if (watcher) + bool success = true; + AZStd::vector fileBuffer; + const AZ::IO::Path workingPath{ dirToArchive }; + + for (const auto& fileName : foundFiles.GetValue()) { - // callback requires output captured from 7z - if (captureOutput) + bool thisSuccess = false; + + AZ::IO::PathView relativePath = AZ::IO::PathView{ fileName }.LexicallyRelative(workingPath); + + AZ::IO::Path fullPath = (workingPath / relativePath); + if (ArchiveUtils::ReadFile(fullPath, AZ::IO::OpenMode::ModeRead, fileBuffer)) { - AZStd::string consoleBuffer; - while (watcher->IsProcessRunning(&exitCode)) - { - if (!taskHandle.IsNull()) - { - AZStd::unique_lock lock(m_threadControlMutex); - if (m_threadInfoMap[taskHandle].shouldStop) - { - watcher->TerminateProcess(static_cast(SevenZipExitCode::UserStoppedProcess)); - } - } - watcher->WaitForProcessToExit(g_sleepDuration, &exitCode); - AZ::u32 outputSize = watcher->GetCommunicator()->PeekOutput(); - if (outputSize) - { - consoleBuffer.resize(outputSize); - watcher->GetCommunicator()->ReadOutput(consoleBuffer.data(), outputSize); - consoleOutput += consoleBuffer; - } - } + int result = archive->UpdateFile( + relativePath.Native(), fileBuffer.data(), fileBuffer.size(), s_compressionMethod, + s_compressionLevel, s_compressionCodec); + + thisSuccess = (result == AZ::IO::ZipDir::ZD_ERROR_SUCCESS); + AZ_Error( + s_traceName, thisSuccess, "Error %d encountered while adding '%s' to archive '%.*s'", result, fileName.c_str(), + AZ_STRING_ARG(archive->GetFullPath().Native())); } else { - ConsoleEchoCommunicator echoCommunicator(watcher->GetCommunicator()); - while (watcher->IsProcessRunning(&exitCode)) - { - if (!taskHandle.IsNull()) - { - AZStd::unique_lock lock(m_threadControlMutex); - if (m_threadInfoMap[taskHandle].shouldStop) - { - watcher->TerminateProcess(static_cast(SevenZipExitCode::UserStoppedProcess)); - } - } - watcher->WaitForProcessToExit(g_sleepDuration, &exitCode); - echoCommunicator.Pump(); - } + AZ_Error( + s_traceName, false, "Error encountered while reading '%s' to add to archive '%.*s'", fileName.c_str(), + AZ_STRING_ARG(archive->GetFullPath().Native())); } + + success = (success && thisSuccess); } - if (taskHandle.IsNull()) + archive.reset(); + p.set_value(success); + }; + + // Async task... + std::promise p; + std::future f = p.get_future(); + + AZStd::thread_desc threadDesc; + threadDesc.m_name = "Archive Task (Create)"; + m_threads.emplace_back(threadDesc, FnCreateArchive, AZStd::move(p)); + return f; + } + + + std::future ArchiveComponent::ExtractArchive( + const AZStd::string& archivePath, + const AZStd::string& destinationPath) + { + if (!CheckParamsForExtract(archivePath, destinationPath)) + { + std::promise p; + p.set_value(false); + return p.get_future(); + } + + auto FnExtractArchive = [this, archivePath, destinationPath](std::promise&& p) -> void + { + auto archive = m_archive->OpenArchive(archivePath, {}, AZ::IO::INestedArchive::FLAGS_READ_ONLY); + if (!archive) { - respCallback(exitCode == static_cast(SevenZipExitCode::NoError), AZStd::move(consoleOutput)); + AZ_Error(s_traceName, false, "Failed to open archive file '%s'", archivePath.c_str()); + p.set_value(false); + return; + } + + AZStd::vector filesInArchive; + if (int result = archive->ListAllFiles(filesInArchive); result != AZ::IO::ZipDir::ZD_ERROR_SUCCESS) + { + AZ_Error(s_traceName, false, "Failed to get list of files in archive '%s'", archivePath.c_str()); + p.set_value(false); + return; + } + + AZStd::vector fileBuffer; + AZ::IO::Path destination{ destinationPath }; + AZ::u64 fileSize = 0; + AZ::u64 numFilesWritten = 0; + AZ::u64 bytesWritten = 0; + AZ::IO::INestedArchive::Handle srcHandle{}; + AZ::IO::HandleType dstHandle = AZ::IO::InvalidHandle; + constexpr AZ::IO::OpenMode openMode = + (AZ::IO::OpenMode::ModeCreatePath | AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeUpdate); + + for (const auto& filePath : filesInArchive) + { + srcHandle = archive->FindFile(filePath.Native()); + AZ_Assert(srcHandle != nullptr, "File '%s' does not exist inside archive '%s'", filePath.c_str(), archivePath.c_str()); + + fileSize = (srcHandle != nullptr) ? archive->GetFileSize(srcHandle) : 0; + fileBuffer.resize_no_construct(fileSize); + if (auto result = archive->ReadFile(srcHandle, fileBuffer.data()); result != AZ::IO::ZipDir::ZD_ERROR_SUCCESS) + { + AZ_Error( + s_traceName, false, "Failed to read file '%s' in archive '%s' with error %d", filePath.c_str(), archivePath.c_str(), + result); + continue; + } + + AZ::IO::Path destinationFile = destination / filePath; + if (!m_fileIO->Open(destinationFile.c_str(), openMode, dstHandle)) + { + AZ_Error(s_traceName, false, "Failed to open '%s' for writing", destinationFile.c_str()); + continue; + } + + if (!m_fileIO->Write(dstHandle, fileBuffer.data(), fileSize, &bytesWritten)) + { + AZ_Error(s_traceName, false, "Failed to write destination file '%s'", destinationFile.c_str()); + } + else if (bytesWritten == fileSize) + { + ++numFilesWritten; + } + + m_fileIO->Close(dstHandle); + } + + p.set_value(numFilesWritten == filesInArchive.size()); + }; + + // Async task... + std::promise p; + std::future f = p.get_future(); + + AZStd::thread_desc threadDesc; + threadDesc.m_name = "Archive Task (Extract)"; + m_threads.emplace_back(threadDesc, FnExtractArchive, AZStd::move(p)); + return f; + } + + + std::future ArchiveComponent::ExtractFile( + const AZStd::string& archivePath, + const AZStd::string& fileInArchive, + const AZStd::string& destinationPath) + { + if (!CheckParamsForExtract(archivePath, destinationPath)) + { + std::promise p; + p.set_value(false); + return p.get_future(); + } + + auto FnExtractFile = [this, archivePath, fileInArchive, destinationPath](std::promise&& p) -> void + { + auto archive = m_archive->OpenArchive(archivePath, {}, AZ::IO::INestedArchive::FLAGS_READ_ONLY); + if (!archive) + { + AZ_Error(s_traceName, false, "Failed to open archive file '%s'", archivePath.c_str()); + p.set_value(false); + return; + } + + AZ::IO::INestedArchive::Handle fileHandle = archive->FindFile(fileInArchive); + if (!fileHandle) + { + AZ_Error(s_traceName, false, "File '%s' does not exist inside archive '%s'", fileInArchive.c_str(), archivePath.c_str()); + p.set_value(false); + return; + } + + AZ::u64 fileSize = archive->GetFileSize(fileHandle); + AZStd::vector fileBuffer; + fileBuffer.resize_no_construct(fileSize); + + if (auto result = archive->ReadFile(fileHandle, fileBuffer.data()); result != AZ::IO::ZipDir::ZD_ERROR_SUCCESS) + { + AZ_Error( + s_traceName, false, "Failed to read file '%s' in archive '%s' with error %d", fileInArchive.c_str(), + archivePath.c_str(), result); + p.set_value(false); + return; + } + + AZ::IO::HandleType destFileHandle = AZ::IO::InvalidHandle; + AZ::IO::Path destinationFile{ destinationPath }; + destinationFile /= fileInArchive; + AZ::IO::OpenMode openMode = (AZ::IO::OpenMode::ModeCreatePath | AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeUpdate); + if (!m_fileIO->Open(destinationFile.c_str(), openMode, destFileHandle)) + { + AZ_Error(s_traceName, false, "Failed to open destination file '%s' for writing", destinationFile.c_str()); + p.set_value(false); + return; + } + + AZ::u64 bytesWritten = 0; + if (!m_fileIO->Write(destFileHandle, fileBuffer.data(), fileSize, &bytesWritten)) + { + AZ_Error(s_traceName, false, "Failed to write destination file '%s'", destinationFile.c_str()); + } + + m_fileIO->Close(destFileHandle); + p.set_value(bytesWritten == fileSize); + }; + + // Async task... + std::promise p; + std::future f = p.get_future(); + + AZStd::thread_desc threadDesc; + threadDesc.m_name = "Archive Task (Extract Single)"; + m_threads.emplace_back(threadDesc, FnExtractFile, AZStd::move(p)); + return f; + } + + + bool ArchiveComponent::ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& outFileEntries) + { + if (!m_fileIO || !m_archive) + { + return false; + } + + if (!m_fileIO->Exists(archivePath.c_str())) + { + AZ_Error(s_traceName, false, "Archive '%s' does not exist!", archivePath.c_str()); + return false; + } + + auto archive = m_archive->OpenArchive(archivePath, {}, AZ::IO::INestedArchive::FLAGS_READ_ONLY); + if (!archive) + { + AZ_Error(s_traceName, false, "Failed to open archive file '%s'", archivePath.c_str()); + return false; + } + + AZStd::vector fileEntries; + int result = archive->ListAllFiles(fileEntries); + outFileEntries.clear(); + for (const auto& path : fileEntries) + { + outFileEntries.emplace_back(path.String()); + } + return (result == AZ::IO::ZipDir::ZD_ERROR_SUCCESS); + } + + + std::future ArchiveComponent::AddFileToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& fileToAdd) + { + if (!CheckParamsForAdd(workingDirectory, fileToAdd)) + { + std::promise p; + p.set_value(false); + return p.get_future(); + } + + auto FnAddFileToArchive = [this, archivePath, workingDirectory, fileToAdd](std::promise&& p) -> void + { + auto archive = m_archive->OpenArchive(archivePath); + if (!archive) + { + AZ_Error(s_traceName, false, "Failed to open archive file '%s'", archivePath.c_str()); + p.set_value(false); + return; + } + + AZ::IO::Path workingPath{ workingDirectory }; + AZ::IO::Path fullPath = workingPath / fileToAdd; + AZ::IO::PathView relativePath = AZ::IO::PathView{ fullPath }.LexicallyRelative(workingPath); + + AZStd::vector fileBuffer; + bool success = false; + if (ArchiveUtils::ReadFile(fullPath, AZ::IO::OpenMode::ModeRead, fileBuffer)) + { + int result = archive->UpdateFile( + relativePath.Native(), fileBuffer.data(), fileBuffer.size(), s_compressionMethod, + s_compressionLevel, s_compressionCodec); + + success = (result == AZ::IO::ZipDir::ZD_ERROR_SUCCESS); + AZ_Error( + s_traceName, success, "Error %d encountered while adding '%s' to archive '%.*s'", result, fileToAdd.c_str(), + AZ_STRING_ARG(archive->GetFullPath().Native())); } else { - AZ::TickBus::QueueFunction(respCallback, (exitCode == static_cast(SevenZipExitCode::NoError)), AZStd::move(consoleOutput)); + AZ_Error( + s_traceName, false, "Error encountered while reading '%s' to add to archive '%.*s'", fileToAdd.c_str(), + AZ_STRING_ARG(archive->GetFullPath().Native())); } - if (!taskHandle.IsNull()) - { - AZStd::unique_lock lock(m_threadControlMutex); - ThreadInfo& tInfo = m_threadInfoMap[taskHandle]; - tInfo.threads.erase(AZStd::this_thread::get_id()); - m_cv.notify_all(); - } + archive.reset(); + p.set_value(success); }; - if (!taskHandle.IsNull()) - { - AZStd::thread processThread(sevenZJob); - AZStd::unique_lock lock(m_threadControlMutex); - ThreadInfo& info = m_threadInfoMap[taskHandle]; - m_cv.wait(lock, [&info, &processThread]() { - return info.threads.find(processThread.get_id()) != info.threads.end(); - }); - processThread.detach(); - } - else - { - sevenZJob(); - } + + // Async task... + std::promise p; + std::future f = p.get_future(); + + AZStd::thread_desc threadDesc; + threadDesc.m_name = "Archive Task (Add Single)"; + m_threads.emplace_back(threadDesc, FnAddFileToArchive, AZStd::move(p)); + return f; } + + + std::future ArchiveComponent::AddFilesToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& listFilePath) + { + if (!CheckParamsForAdd(workingDirectory, listFilePath)) + { + std::promise p; + p.set_value(false); + return p.get_future(); + } + + auto FnAddFilesToArchive = [this, archivePath, workingDirectory, listFilePath](std::promise&& p) -> void + { + auto archive = m_archive->OpenArchive(archivePath); + if (!archive) + { + AZ_Error(s_traceName, false, "Failed to open archive file '%s'", archivePath.c_str()); + p.set_value(false); + return; + } + + bool success = true; // starts true and turns false when any error is encountered. + AZ::IO::Path basePath{ workingDirectory }; + + auto PerLineCallback = [&success, &basePath, &archive](AZStd::string_view filePathLine) -> void + { + AZStd::vector fileBuffer; + AZ::IO::Path fullPath = (basePath / filePathLine); + if (ArchiveUtils::ReadFile(fullPath, AZ::IO::OpenMode::ModeRead, fileBuffer)) + { + int result = archive->UpdateFile( + filePathLine, fileBuffer.data(), fileBuffer.size(), s_compressionMethod, + s_compressionLevel, s_compressionCodec); + + bool thisSuccess = (result == AZ::IO::ZipDir::ZD_ERROR_SUCCESS); + success = (success && thisSuccess); + AZ_Error( + s_traceName, thisSuccess, "Error %d encountered while adding '%.*s' to archive '%.*s'", result, + AZ_STRING_ARG(filePathLine), AZ_STRING_ARG(archive->GetFullPath().Native())); + } + else + { + AZ_Error( + s_traceName, false, "Error encountered while reading '%.*s' to add to archive '%.*s'", AZ_STRING_ARG(filePathLine), + AZ_STRING_ARG(archive->GetFullPath().Native())); + } + }; + + ArchiveUtils::ProcessFileList(listFilePath, PerLineCallback); + + archive.reset(); + p.set_value(success); + }; + + // Async task... + std::promise p; + std::future f = p.get_future(); + + AZStd::thread_desc threadDesc; + threadDesc.m_name = "Archive Task (Add)"; + m_threads.emplace_back(threadDesc, FnAddFilesToArchive, AZStd::move(p)); + return f; + } + + + bool ArchiveComponent::CheckParamsForAdd(const AZStd::string& directory, const AZStd::string& file) + { + if (!m_fileIO || !m_archive) + { + return false; + } + + if (!m_fileIO->IsDirectory(directory.c_str())) + { + AZ_Error( + s_traceName, false, "Working directory '%s' is not a directory or doesn't exist!", directory.c_str()); + return false; + } + + if (!file.empty()) + { + auto filePath = AZ::IO::Path{ directory } / file; + if (!m_fileIO->Exists(filePath.c_str()) || m_fileIO->IsDirectory(filePath.c_str())) + { + AZ_Error(s_traceName, false, "File list '%s' is a directory or doesn't exist!", filePath.c_str()); + return false; + } + } + + return true; + } + + bool ArchiveComponent::CheckParamsForExtract(const AZStd::string& archive, const AZStd::string& directory) + { + if (!m_fileIO || !m_archive) + { + return false; + } + + if (!m_fileIO->Exists(archive.c_str())) + { + AZ_Error(s_traceName, false, "Archive '%s' does not exist!", archive.c_str()); + return false; + } + + if (!m_fileIO->Exists(directory.c_str())) + { + if (!m_fileIO->CreatePath(directory.c_str())) + { + AZ_Error(s_traceName, false, "Failed to create destination directory '%s'", directory.c_str()); + return false; + } + } + + return true; + } + + bool ArchiveComponent::CheckParamsForCreate(const AZStd::string& archive, const AZStd::string& directory) + { + if (!m_fileIO || !m_archive) + { + return false; + } + + if (m_fileIO->Exists(archive.c_str())) + { + AZ_Error(s_traceName, false, "Archive file '%s' already exists, cannot create a new archive there!"); + return false; + } + + if (!m_fileIO->IsDirectory(directory.c_str())) + { + AZ_Error(s_traceName, false, "Directory '%s' is not a directory or doesn't exist!", directory.c_str()); + return false; + } + + return true; + } + } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.h index fc344fc5a6..e2b437bcf2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.h @@ -10,80 +10,76 @@ #include #include +#include #include #include #include #include +#include #include namespace AzToolsFramework { - enum class SevenZipExitCode : AZ::u32 - { - NoError = 0, - Warning = 1, - FatalError = 2, - CommandLineError = 7, - NotEnoughMemory = 8, - UserStoppedProcess = 255 - }; - - // the ArchiveComponent's job is to execute zip commands. - // it parses the status of zip commands and returns results. + // the ArchiveComponent's job is to create and manipulate zip archives. class ArchiveComponent : public AZ::Component - , private ArchiveCommands::Bus::Handler + , private ArchiveCommandsBus::Handler { public: - AZ_COMPONENT(ArchiveComponent, "{A19EEA33-3736-447F-ACF7-DAA4B6A179AA}") + AZ_COMPONENT(ArchiveComponent, "{A19EEA33-3736-447F-ACF7-DAA4B6A179AA}"); ArchiveComponent() = default; ~ArchiveComponent() override = default; + ArchiveComponent(const ArchiveComponent&) = delete; + ArchiveComponent& operator=(const ArchiveComponent&) = delete; + ////////////////////////////////////////////////////////////////////////// // AZ::Component overrides void Activate() override; void Deactivate() override; ////////////////////////////////////////////////////////////////////////// - private: + + protected: static void Reflect(AZ::ReflectContext* context); ////////////////////////////////////////////////////////////////////////// - // ArchiveCommands::Bus::Handler overrides - void CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) override; - bool ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) override; - void ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) override; - void ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) override; - void ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& fileEntries, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector& fileEntries) override; - void AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd) override; - bool AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) override; - void AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void CancelTasks(AZ::Uuid taskHandle) override; + // ArchiveCommandsBus::Handler overrides + [[nodiscard]] std::future CreateArchive( + const AZStd::string& archivePath, + const AZStd::string& dirToArchive) override; + + [[nodiscard]] std::future ExtractArchive( + const AZStd::string& archivePath, + const AZStd::string& destinationPath) override; + + [[nodiscard]] std::future ExtractFile( + const AZStd::string& archivePath, + const AZStd::string& fileInArchive, + const AZStd::string& destinationPath) override; + + bool ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& outFileEntries) override; + + [[nodiscard]] std::future AddFileToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& fileToAdd) override; + + [[nodiscard]] std::future AddFilesToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& listFilePath) override; ////////////////////////////////////////////////////////////////////////// - - // Launches the input zip exe as a background child process in a detached background thread, if the task handle is not null - // otherwise launches input zip exe in the calling thread. - void LaunchZipExe(const AZStd::string& exePath, const AZStd::string& commandLineArgs, const ArchiveResponseOutputCallback& respCallback, AZ::Uuid taskHandle = AZ::Uuid::CreateNull(), const AZStd::string& workingDir = "", bool captureOutput = false); - AZStd::string m_zipExePath; - AZStd::string m_unzipExePath; + private: + AZ::IO::FileIOBase* m_fileIO = nullptr; + AZ::IO::IArchive* m_archive = nullptr; + AZStd::vector m_threads; - // Struct for tracking background threads/tasks - struct ThreadInfo - { - bool shouldStop = false; - AZStd::set threads; - }; - - AZStd::mutex m_threadControlMutex; // Guards m_threadInfoMap - AZStd::condition_variable m_cv; - AZStd::unordered_map m_threadInfoMap; + bool CheckParamsForAdd(const AZStd::string& directory, const AZStd::string& file); + bool CheckParamsForExtract(const AZStd::string& archive, const AZStd::string& directory); + bool CheckParamsForCreate(const AZStd::string& archive, const AZStd::string& directory); }; + } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.cpp index f82724a721..972e9d588f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.cpp @@ -16,91 +16,62 @@ namespace AzToolsFramework void NullArchiveComponent::Activate() { - ArchiveCommands::Bus::Handler::BusConnect(); + ArchiveCommandsBus::Handler::BusConnect(); } void NullArchiveComponent::Deactivate() { - ArchiveCommands::Bus::Handler::BusDisconnect(); + ArchiveCommandsBus::Handler::BusDisconnect(); } - bool NullArchiveComponent::ExtractArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, bool /*extractWithRootDirectory*/) + std::future DefaultFuture() + { + std::promise p; + p.set_value(false); + return p.get_future(); + } + + std::future NullArchiveComponent::CreateArchive( + const AZStd::string& /*archivePath*/, + const AZStd::string& /*dirToArchive*/) + { + return DefaultFuture(); + } + + std::future NullArchiveComponent::ExtractArchive( + const AZStd::string& /*archivePath*/, + const AZStd::string& /*destinationPath*/) + { + return DefaultFuture(); + } + + std::future NullArchiveComponent::ExtractFile( + const AZStd::string& /*archivePath*/, + const AZStd::string& /*fileInArchive*/, + const AZStd::string& /*destinationPath*/) + { + return DefaultFuture(); + } + + bool NullArchiveComponent::ListFilesInArchive(const AZStd::string& /*archivePath*/, AZStd::vector& /*outFileEntries*/) { return false; } - void NullArchiveComponent::ExtractArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseCallback& respCallback) + std::future NullArchiveComponent::AddFileToArchive( + const AZStd::string& /*archivePath*/, + const AZStd::string& /*fileToAdd*/, + const AZStd::string& /*pathInArchive*/) { - AZ::TickBus::QueueFunction(respCallback, false); + return DefaultFuture(); } - void NullArchiveComponent::ExtractArchiveOutput(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - void NullArchiveComponent::ExtractArchiveWithoutRoot(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - void NullArchiveComponent::ExtractFile(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileInArchive*/, const AZStd::string& /*destinationPath*/, bool /*overWrite*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - // Always report we failed to extract - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - bool NullArchiveComponent::ExtractFileBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileInArchive*/, const AZStd::string& /*destinationPath*/, bool /*overWrite*/) - { - return false; - } - - void NullArchiveComponent::ListFilesInArchive(const AZStd::string& /*archivePath*/, AZStd::vector& /*consoleOutput*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - // Always report we failed to extract - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - bool NullArchiveComponent::ListFilesInArchiveBlocking(const AZStd::string& /*archivePath*/, AZStd::vector& /*consoleOutput*/) - { - return false; - } - - void NullArchiveComponent::AddFileToArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileToAdd*/, const AZStd::string& /*pathInArchive*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - // Always report we failed to extract - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - bool NullArchiveComponent::AddFileToArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileToAdd*/, const AZStd::string& /*pathInArchive*/) - { - return false; - } - - bool NullArchiveComponent::AddFilesToArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*workingDirectory*/, const AZStd::string& /*listFilePath*/) - { - return false; - } - - void NullArchiveComponent::AddFilesToArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*workingDirectory*/, const AZStd::string& /*listFilePath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - // Always report we failed to extract - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - void NullArchiveComponent::CreateArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*dirToArchive*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - // Always report we failed to extract - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - bool NullArchiveComponent::CreateArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*dirToArchive*/) - { - return false; - } - - void NullArchiveComponent::CancelTasks(AZ::Uuid /*taskHandle*/) + std::future NullArchiveComponent::AddFilesToArchive( + const AZStd::string& /*archivePath*/, + const AZStd::string& /*workingDirectory*/, + const AZStd::string& /*listFilePath*/) { + return DefaultFuture(); } void NullArchiveComponent::Reflect(AZ::ReflectContext* context) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.h index 2023490351..9ce33d0c85 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.h @@ -15,7 +15,7 @@ namespace AzToolsFramework { class NullArchiveComponent : public AZ::Component - , private ArchiveCommands::Bus::Handler + , private ArchiveCommandsBus::Handler { public: AZ_COMPONENT(NullArchiveComponent, "{D665B6B1-5FF4-4203-B19F-BBDB82587129}") @@ -32,23 +32,31 @@ namespace AzToolsFramework static void Reflect(AZ::ReflectContext* context); ////////////////////////////////////////////////////////////////////////// - // ArchiveCommands::Bus::Handler overrides - // ArchiveCommands::Bus::Handler overrides - void CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) override; - bool ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) override; - void ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) override; - void ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) override; - void ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& consoleOutput, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector& consoleOutput) override; - void AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& fileToAdd, const AZStd::string& pathInArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& fileToAdd, const AZStd::string& pathInArchive) override; - bool AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) override; - void AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void CancelTasks(AZ::Uuid taskHandle) override; + // ArchiveCommandsBus::Handler overrides + [[nodiscard]] std::future CreateArchive( + const AZStd::string& archivePath, + const AZStd::string& dirToArchive) override; + + [[nodiscard]] std::future ExtractArchive( + const AZStd::string& archivePath, + const AZStd::string& destinationPath) override; + + [[nodiscard]] std::future ExtractFile( + const AZStd::string& archivePath, + const AZStd::string& fileInArchive, + const AZStd::string& destinationPath) override; + + bool ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& outFileEntries) override; + + [[nodiscard]] std::future AddFileToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& fileToAdd) override; + + [[nodiscard]] std::future AddFilesToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& listFilePath) override; ////////////////////////////////////////////////////////////////////////// }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp index 7083737cf7..8924907e81 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp @@ -32,12 +32,10 @@ namespace AzToolsFramework const int NumOfBytesInMB = 1024 * 1024; const int ManifestFileSizeBufferInBytes = 10 * 1024; // 10 KB const float AssetCatalogFileSizeBufferPercentage = 1.0f; - using ArchiveCommandsBus = AzToolsFramework::ArchiveCommands::Bus; using AssetCatalogRequestBus = AZ::Data::AssetCatalogRequestBus; const char AssetBundleComponent::DeltaCatalogName[] = "DeltaCatalog.xml"; - constexpr int SleepTimeMS = 250; constexpr int InjectFileRetryCount = 4; @@ -136,7 +134,7 @@ namespace AzToolsFramework AZ_TracePrintf(logWindowName, "Gathering file entries in source pak file \"%s\".\n", sourcePak.c_str()); bool result = false; AZStd::vector fileEntries; - ArchiveCommandsBus::BroadcastResult(result, &AzToolsFramework::ArchiveCommands::ListFilesInArchiveBlocking, normalizedSourcePakPath, fileEntries); + ArchiveCommandsBus::BroadcastResult(result, &AzToolsFramework::ArchiveCommandsBus::Events::ListFilesInArchive, normalizedSourcePakPath, fileEntries); // This ebus currently always returns false as the result, as it is believed that the 7z process is // being terminated by the user instead of ending gracefully. Check against an empty fileList instead // as a result. @@ -606,15 +604,17 @@ namespace AzToolsFramework { AZ_TracePrintf(logWindowName, "Injecting file (%s) into bundle (%s).\n", filePath.c_str(), archiveFilePath.c_str()); bool fileAddedToArchive = false; + std::future fileAdded; int retryCount = InjectFileRetryCount; + while (!fileAddedToArchive && retryCount) { - ArchiveCommandsBus::BroadcastResult(fileAddedToArchive, &AzToolsFramework::ArchiveCommands::AddFileToArchiveBlocking, archiveFilePath, workingDirectory, filePath); + ArchiveCommandsBus::BroadcastResult(fileAdded, &AzToolsFramework::ArchiveCommandsBus::Events::AddFileToArchive, archiveFilePath, workingDirectory, filePath); --retryCount; + fileAddedToArchive = fileAdded.get(); if (!fileAddedToArchive && retryCount) { AZ_Error(logWindowName, false, "Failed to insert file (%s) into bundle (%s). Retrying.", filePath.c_str(), archiveFilePath.c_str()); - AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(SleepTimeMS)); } } @@ -627,7 +627,11 @@ namespace AzToolsFramework bool AssetBundleComponent::InjectFile(const AZStd::string& filePath, const AZStd::string& sourcePak) { - return InjectFile(filePath, sourcePak, ""); + // When no working directory is specified, assume that the file being injected goes into the root of the archive. + // The filePath should be an absolute path, making the workingDirectory be the path leading up to the file. + AZ::IO::PathView fullFilePath{ filePath, AZ::IO::PosixPathSeparator }; + AZ::IO::Path workingDir{ fullFilePath.ParentPath() }; + return InjectFile(filePath, sourcePak, workingDir.c_str()); } bool AssetBundleComponent::InjectFiles(const AZStd::vector& fileEntries, const AZStd::string& sourcePak, const char* workingDirectory) @@ -668,8 +672,9 @@ namespace AzToolsFramework } } - bool filesAddedToArchive = false; - AzToolsFramework::ArchiveCommandsBus::BroadcastResult(filesAddedToArchive, &AzToolsFramework::ArchiveCommands::AddFilesToArchiveBlocking, sourcePak, workingDirectory, listFilePath); + std::future filesAdded; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(filesAdded, &AzToolsFramework::ArchiveCommands::AddFilesToArchive, sourcePak, workingDirectory, listFilePath); + bool filesAddedToArchive = filesAdded.get(); if (!filesAddedToArchive) { AZ_Error(logWindowName, false, "Failed to insert files into bundle (%s).\n", sourcePak.c_str()); @@ -688,7 +693,6 @@ namespace AzToolsFramework { // open the manifest and deserialize it bool manifestExtracted = false; - const bool overwriteExisting = true; TemporaryDir tempDir(sourcePak); if (!tempDir.m_result) @@ -698,7 +702,10 @@ namespace AzToolsFramework AZStd::string manifestFilePath; AzFramework::StringFunc::Path::ConstructFull(tempDir.m_tempFolderPath.c_str(), AzFramework::AssetBundleManifest::s_manifestFileName, manifestFilePath, true); - ArchiveCommandsBus::BroadcastResult(manifestExtracted, &ArchiveCommandsBus::Events::ExtractFileBlocking, sourcePak, AzFramework::AssetBundleManifest::s_manifestFileName, tempDir.m_tempFolderPath, overwriteExisting); + + std::future extractResult; + ArchiveCommandsBus::BroadcastResult(extractResult, &ArchiveCommandsBus::Events::ExtractFile, sourcePak, AzFramework::AssetBundleManifest::s_manifestFileName, tempDir.m_tempFolderPath); + manifestExtracted = extractResult.get(); if (!manifestExtracted) { AZ_Error(logWindowName, false, "Failed to extract existing manifest from archive \"%s\".", sourcePak.c_str()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.h index 307777cc1b..17a9dd40f5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.h @@ -57,7 +57,7 @@ namespace AzToolsFramework //! Returns true if the file at filePath was successfully injected into the bundle at sourcePak static bool InjectFile(const AZStd::string& filePath, const AZStd::string& sourcePak, const char* workingDirectory); - //! Inject the files with relative filePaths which espect to the working directory into the bundle at sourcePak + //! Inject the files with relative filePaths with respect to the working directory into the bundle at sourcePak //! Returns true if the file at filePath was successfully injected into the bundle at sourcePak static bool InjectFiles(const AZStd::vector& fileEntries, const AZStd::string& sourcePak, const char* workingDirectory); diff --git a/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/Archive/ArchiveComponent_Linux.cpp b/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/Archive/ArchiveComponent_Linux.cpp deleted file mode 100644 index cc8b9492e8..0000000000 --- a/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/Archive/ArchiveComponent_Linux.cpp +++ /dev/null @@ -1,230 +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 - -namespace AzToolsFramework -{ - namespace Platform - { - [[maybe_unused]] static const char ErrorChannel[] = "ArchiveComponent_Linux"; - - static const char ZipExePath[] = R"(/usr/bin/zip)"; - static const char UnzipExePath[] = R"(/usr/bin/unzip)"; - - static const char CreateArchiveCmd[] = "-r \"%s\" . -i *"; - - static const char ExtractArchiveCmd[] = R"(-o "%s" -d "%s")"; - - static const char AddFileCmd[] = R"("%s" "%s")"; - - static const char ExtractFileCmd[] = R"(%s "%s" %s)"; - static const char ExtractFileDestination[] = R"(%s "%s" "%s" -d "%s")"; - static const char ExtractOverwrite[] = "-o"; - static const char ExtractSkipExisting[] = "-n"; - static const char ListFilesInArchiveCmd[] = "-l %s"; - - AZStd::string GetZipExePath() - { - return ZipExePath; - } - - AZStd::string GetUnzipExePath() - { - return UnzipExePath; - } - - AZ::Outcome MakePath(const AZStd::string& path) - { - // Create the folder if it does not already exist - if (!AZ::IO::FileIOBase::GetInstance()->Exists(path.c_str())) - { - auto result = AZ::IO::FileIOBase::GetInstance()->CreatePath(path.c_str()); - if (!result) - { - return AZ::Failure(AZStd::string::format("Path creation failed. Input path: %s \n", path.c_str())); - } - } - - return AZ::Success(path); - } - - AZ::Outcome MakeCreateArchivePath(const AZStd::string& archivePath) - { - // Remove the file name from the input path - // /some/folder/path/archive.zip -> /some/folder/path/ - AZStd::string strippedArchivePath = archivePath; - AzFramework::StringFunc::Path::StripFullName(strippedArchivePath); - - if (strippedArchivePath.empty()) - { - return AZ::Failure(AZStd::string::format("Stripped path name is empty. Cancelling path creation. Input path: %s\n", archivePath.c_str())); - } - - return MakePath(strippedArchivePath); - } - - AZ::Outcome MakeExtractArchivePath(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot) - { - if(!includeRoot) - { - // Create the folder for the input destination path with no modifications - // /path/to/destination/ - return MakePath(destinationPath); - } - - // Get the name of the input archive. This will be the name of the root folder for the archive extraction - // /some/folder/path/archive.zip -> archive - AZStd::string zipFileName; - bool result = AzFramework::StringFunc::Path::GetFileName(archivePath.c_str(), zipFileName); - if(!result) - { - return AZ::Failure(AZStd::string::format("Failed to get name of zip file from the archive path. Cancelling path creation. \n Input Archive Path: %s \n", archivePath.c_str())); - } - - // Append the root folder name to the end of the destination path - // /path/to/destination/ + archive -> /path/to/destination/archive - AZStd::string destinationPathWithRoot; - result = AzFramework::StringFunc::Path::Join(destinationPath.c_str(), zipFileName.c_str(), destinationPathWithRoot); - if(!result) - { - return AZ::Failure(AZStd::string::format("Failed to append zip file name to the destination path. Cancelling path creation. \n Destination Path: %s \n Zip file name: %s \n", destinationPath.c_str(), zipFileName.c_str())); - } - - // Append a separator so that it is formatted like a folder - // /path/to/destination/archive -> /path/to/destination/archive/ - AzFramework::StringFunc::Path::AppendSeparator(destinationPathWithRoot); - return MakePath(destinationPathWithRoot); - } - - AZStd::string GetCreateArchiveCommand(const AZStd::string& archivePath, const AZStd::string& dirToArchive) - { - auto pathCreationResult = MakeCreateArchivePath(archivePath); - if (!pathCreationResult) - { - AZ_Error(ErrorChannel, false, "%s", pathCreationResult.GetError().c_str()); - return ""; - } - AZ_UNUSED(dirToArchive); - return AZStd::string::format(CreateArchiveCmd, archivePath.c_str()); - } - - AZStd::string GetExtractArchiveCommand(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot) - { - auto pathCreationResult = MakeExtractArchivePath(archivePath, destinationPath, includeRoot); - if (!pathCreationResult) - { - AZ_Error(ErrorChannel, false, "%s", pathCreationResult.GetError().c_str()); - return ""; - } - - return AZStd::string::format(ExtractArchiveCmd, archivePath.c_str(), pathCreationResult.GetValue().c_str()); - } - - AZStd::string GetAddFilesToArchiveCommand(const AZStd::string& /*archivePath*/, const AZStd::string& /*listFilePath*/) - { - // Adding files into a archive using a list file is not currently supported - return {}; - } - - bool IsAddFilesToArchiveCommandSupported() - { - // Adding files into a archive using a list file is not currently supported - return false; - } - - AZStd::string GetAddFileToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& file) - { - if (!MakeCreateArchivePath(archivePath).IsSuccess()) - { - AZ_Error(ErrorChannel, false, "Unable to make path for ( %s ).\n", archivePath.c_str()); - return {}; - } - return AZStd::string::format(AddFileCmd, archivePath.c_str(), file.c_str()); - } - - AZStd::string GetExtractFileCommand(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) - { - AZStd::string commandLineArgs; - if (destinationPath.empty()) - { - // Extract file in archive from archive path to the current directory, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileCmd, overWrite ? ExtractOverwrite : ExtractSkipExisting, archivePath.c_str(), fileInArchive.c_str()); - } - else - { - if (!MakePath(destinationPath).IsSuccess()) - { - AZ_Error(ErrorChannel, false, "Unable to make path ( %s ).\n", destinationPath.c_str()); - return {}; - } - // Extract file in archive from archive path to destinationPath, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileDestination, overWrite ? ExtractOverwrite : ExtractSkipExisting, archivePath.c_str(), fileInArchive.c_str(), destinationPath.c_str()); - } - - return commandLineArgs; - } - - AZStd::string GetListFilesInArchiveCommand(const AZStd::string& archivePath) - { - AZStd::string commandLineArgs = AZStd::string::format(ListFilesInArchiveCmd, archivePath.c_str()); - return commandLineArgs; - } - - /* - Sample Console Output of the unzip list command - - Archive: /var/folders/1q/12nyzqc913qgm532y2c98mnm6w4_qv/T/ArchiveTests-ra8oMy/TestArchive.pak - Length Date Time Name - --------- ---------- ----- ---- - 0 10-14-2019 15:22 testfolder/ - 1 10-14-2019 15:22 testfolder/folderfile.txt - 1 10-14-2019 15:22 basicfile.txt - 1 10-14-2019 15:22 basicfile2.txt - 0 10-14-2019 15:22 testfolder2/ - 1 10-14-2019 15:22 testfolder2/sharedfolderfile2.txt - 1 10-14-2019 15:22 testfolder2/sharedfolderfile.txt - 0 10-14-2019 15:22 testfolder3/ - 0 10-14-2019 15:22 testfolder3/testfolder4/ - 1 10-14-2019 15:22 testfolder3/testfolder4/depthfile.bat - --------- ------- - 6 10 files - */ - - void ParseConsoleOutputFromListFilesInArchive(const AZStd::string& consoleOutput, AZStd::vector& fileEntries) - { - AZStd::vector fileEntryData; - AzFramework::StringFunc::Tokenize(consoleOutput.c_str(), fileEntryData, "\n"); - int startingLineIdx = 3; // first line that might contain the file name - for (size_t lineIdx = startingLineIdx; lineIdx < fileEntryData.size(); ++lineIdx) - { - AZStd::string& line = fileEntryData[lineIdx]; - AZStd::vector lineEntryData; - AzFramework::StringFunc::Tokenize(line.c_str(), lineEntryData, " "); - AZStd::string& fileName = lineEntryData.back(); - - if(fileName.back() == AZ_CORRECT_FILESYSTEM_SEPARATOR) - { - // if the filename ends with a separator - // than it indicates that this is a directory - continue; - } - - if(fileName.compare("-------") == 0) - { - return; - } - - fileEntries.emplace_back(fileName); - } - } - } // namespace Platform -} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake b/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake index 84d1cf808f..c2c5a11c4c 100644 --- a/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake +++ b/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake @@ -7,5 +7,4 @@ # set(FILES - AzToolsFramework/Archive/ArchiveComponent_Linux.cpp ) diff --git a/Code/Framework/AzToolsFramework/Platform/Mac/AzToolsFramework/Archive/ArchiveComponent_Mac.cpp b/Code/Framework/AzToolsFramework/Platform/Mac/AzToolsFramework/Archive/ArchiveComponent_Mac.cpp deleted file mode 100644 index 67b7b9cf66..0000000000 --- a/Code/Framework/AzToolsFramework/Platform/Mac/AzToolsFramework/Archive/ArchiveComponent_Mac.cpp +++ /dev/null @@ -1,263 +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 - -namespace AzToolsFramework -{ - namespace Platform - { - const char ErrorChannel[] = "ArchiveComponent_OSX"; - - const char ZipExePath[] = R"(/usr/bin/zip)"; - const char UnzipExePath[] = R"(/usr/bin/unzip)"; - - // v Requires investigation, the correct cmd should be R"(-r "%s" "%s/")" but tests fail - const char CreateArchiveCmd[] = R"(-r "%s" .)"; - - const char ExtractArchiveCmd[] = R"(-o "%s" -d "%s")"; - - const char AddFileCmd[] = R"("%s" "%s" -X)"; - const char AddFilesCmd[] = R"("%s" -X %s)"; - - const char ExtractFileCmd[] = R"(%s "%s" %s)"; - const char ExtractFileDestination[] = R"(%s "%s" "%s" -d "%s")"; - const char ExtractOverwrite[] = "-o"; - const char ExtractSkipExisting[] = "-n"; - const char ListFilesInArchiveCmd[] = "-l %s"; - - AZStd::string GetZipExePath() - { - return ZipExePath; - } - - AZStd::string GetUnzipExePath() - { - return UnzipExePath; - } - - AZ::Outcome MakePath(const AZStd::string& path) - { - // Create the folder if it does not already exist - if (!AZ::IO::FileIOBase::GetInstance()->Exists(path.c_str())) - { - auto result = AZ::IO::FileIOBase::GetInstance()->CreatePath(path.c_str()); - if (!result) - { - return AZ::Failure(AZStd::string::format("Path creation failed. Input path: %s \n", path.c_str())); - } - } - - return AZ::Success(path); - } - - AZ::Outcome MakeCreateArchivePath(const AZStd::string& archivePath) - { - // Remove the file name from the input path - // /some/folder/path/archive.zip -> /some/folder/path/ - AZStd::string strippedArchivePath = archivePath; - AzFramework::StringFunc::Path::StripFullName(strippedArchivePath); - - if (strippedArchivePath.empty()) - { - return AZ::Failure(AZStd::string::format("Stripped path name is empty. Cancelling path creation. Input path: %s\n", archivePath.c_str())); - } - - return MakePath(strippedArchivePath); - } - - AZ::Outcome MakeExtractArchivePath(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot) - { - if(!includeRoot) - { - // Create the folder for the input destination path with no modifications - // /path/to/destination/ - return MakePath(destinationPath); - } - - // Get the name of the input archive. This will be the name of the root folder for the archive extraction - // /some/folder/path/archive.zip -> archive - AZStd::string zipFileName; - bool result = AzFramework::StringFunc::Path::GetFileName(archivePath.c_str(), zipFileName); - if(!result) - { - return AZ::Failure(AZStd::string::format("Failed to get name of zip file from the archive path. Cancelling path creation. \n Input Archive Path: %s \n", archivePath.c_str())); - } - - // Append the root folder name to the end of the destination path - // /path/to/destination/ + archive -> /path/to/destination/archive - AZStd::string destinationPathWithRoot; - result = AzFramework::StringFunc::Path::Join(destinationPath.c_str(), zipFileName.c_str(), destinationPathWithRoot); - if(!result) - { - return AZ::Failure(AZStd::string::format("Failed to append zip file name to the destination path. Cancelling path creation. \n Destination Path: %s \n Zip file name: %s \n", destinationPath.c_str(), zipFileName.c_str())); - } - - // Append a separator so that it is formatted like a folder - // /path/to/destination/archive -> /path/to/destination/archive/ - AzFramework::StringFunc::Path::AppendSeparator(destinationPathWithRoot); - return MakePath(destinationPathWithRoot); - } - - AZStd::string GetCreateArchiveCommand(const AZStd::string& archivePath, const AZStd::string& dirToArchive) - { - auto pathCreationResult = MakeCreateArchivePath(archivePath); - if (!pathCreationResult.IsSuccess()) - { - AZ_Error(ErrorChannel, false, pathCreationResult.GetError().c_str()); - return ""; - } - - // LY-116692. Requires proper investigation, the correct format should be: - // AZStd::string::format(CreateArchiveCmd, archivePath.c_str(), dirToArchive.c_str()); - // but unit test ArchiveTest.ListFilesInArchiveBlocking_FilesAtThreeDepths_FilesFound fails - AZ_UNUSED(dirToArchive); - return AZStd::string::format(CreateArchiveCmd, archivePath.c_str()); - } - - AZStd::string GetExtractArchiveCommand(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot) - { - auto pathCreationResult = MakeExtractArchivePath(archivePath, destinationPath, includeRoot); - if (!pathCreationResult) - { - AZ_Error(ErrorChannel, false, pathCreationResult.GetError().c_str()); - return ""; - } - - return AZStd::string::format(ExtractArchiveCmd, archivePath.c_str(), pathCreationResult.GetValue().c_str()); - } - - AZStd::string GetAddFilesToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& listFilePath) - { - auto pathCreationResult = MakeCreateArchivePath(archivePath); - if (!pathCreationResult) - { - AZ_Error(ErrorChannel, false, pathCreationResult.GetError().c_str()); - return ""; - } - AZStd::string fileListStr; - - { - AZ::IO::FileIOStream fileStream(listFilePath.c_str(), AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeText); - if (fileStream.IsOpen()) - { - AZ::IO::SizeType length = fileStream.GetLength(); - AZStd::vector charBuffer; - charBuffer.resize_no_construct(length + 1); - - fileStream.Read(length, charBuffer.data()); - charBuffer.back() = 0; - - fileListStr.append("\""); - fileListStr.insert(1, charBuffer.data()); - AzFramework::StringFunc::Replace(fileListStr, "\n", "\" \""); - fileListStr.append("\""); - } - else - { - AZ_Error(ErrorChannel, false, "Unable to read list file ( %s ) \n", listFilePath.c_str()); - return ""; - } - } - - return AZStd::string::format(AddFilesCmd, archivePath.c_str(), fileListStr.c_str()); - } - - AZStd::string GetAddFileToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& file) - { - auto pathCreationResult = MakeCreateArchivePath(archivePath); - if (!pathCreationResult) - { - AZ_Error(ErrorChannel, false, pathCreationResult.GetError().c_str()); - return ""; - } - - return AZStd::string::format(AddFileCmd, archivePath.c_str(), file.c_str()); - } - - AZStd::string GetExtractFileCommand(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) - { - AZStd::string commandLineArgs; - if (destinationPath.empty()) - { - // Extract file in archive from archive path to the current directory, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileCmd, overWrite ? ExtractOverwrite : ExtractSkipExisting, archivePath.c_str(), fileInArchive.c_str()); - } - else - { - if (!MakePath(destinationPath).IsSuccess()) - { - AZ_Error(ErrorChannel, false, "Unable to make path ( %s ).\n", destinationPath.c_str()); - return ""; - } - // Extract file in archive from archive path to destinationPath, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileDestination, overWrite ? ExtractOverwrite : ExtractSkipExisting, archivePath.c_str(), fileInArchive.c_str(), destinationPath.c_str()); - } - - return commandLineArgs; - } - - AZStd::string GetListFilesInArchiveCommand(const AZStd::string& archivePath) - { - AZStd::string commandLineArgs = AZStd::string::format(ListFilesInArchiveCmd, archivePath.c_str()); - return commandLineArgs; - } - - /* - Sample Console Output of the unzip list command - - Archive: /var/folders/1q/12nyzqc913qgm532y2c98mnm6w4_qv/T/ArchiveTests-ra8oMy/TestArchive.pak - Length Date Time Name - --------- ---------- ----- ---- - 0 10-14-2019 15:22 testfolder/ - 1 10-14-2019 15:22 testfolder/folderfile.txt - 1 10-14-2019 15:22 basicfile.txt - 1 10-14-2019 15:22 basicfile2.txt - 0 10-14-2019 15:22 testfolder2/ - 1 10-14-2019 15:22 testfolder2/sharedfolderfile2.txt - 1 10-14-2019 15:22 testfolder2/sharedfolderfile.txt - 0 10-14-2019 15:22 testfolder3/ - 0 10-14-2019 15:22 testfolder3/testfolder4/ - 1 10-14-2019 15:22 testfolder3/testfolder4/depthfile.bat - --------- ------- - 6 10 files - */ - - void ParseConsoleOutputFromListFilesInArchive(const AZStd::string& consoleOutput, AZStd::vector& fileEntries) - { - AZStd::vector fileEntryData; - AzFramework::StringFunc::Tokenize(consoleOutput.c_str(), fileEntryData, "\n"); - int startingLineIdx = 3; // first line that might contain the file name - for (size_t lineIdx = startingLineIdx; lineIdx < fileEntryData.size(); ++lineIdx) - { - AZStd::string& line = fileEntryData[lineIdx]; - AZStd::vector lineEntryData; - AzFramework::StringFunc::Tokenize(line.c_str(), lineEntryData, " "); - AZStd::string& fileName = lineEntryData.back(); - - if(fileName.back() == AZ_CORRECT_FILESYSTEM_SEPARATOR) - { - // if the filename ends with a separator - // than it indicates that this is a directory - continue; - } - - if(fileName.compare("-------") == 0) - { - return; - } - - fileEntries.emplace_back(fileName); - } - } - - } // namespace Platform -} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake b/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake index 9928584f86..c2c5a11c4c 100644 --- a/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake +++ b/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake @@ -7,5 +7,4 @@ # set(FILES - AzToolsFramework/Archive/ArchiveComponent_Mac.cpp ) diff --git a/Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp b/Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp deleted file mode 100644 index 20f53af18b..0000000000 --- a/Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp +++ /dev/null @@ -1,167 +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 - -namespace AzToolsFramework -{ - namespace Platform - { - const char CreateArchiveCmd[] = R"(a -tzip -mx=1 "%s" -r "%s\*")"; - - // -aos is for skipping extract on existing files - const char ExtractArchiveCmd[] = R"(x -mmt=off "%s" -o"%s\*" -aos)"; - const char ExtractArchiveWithoutRootCmd[] = R"(x -mmt=off "%s" -o"%s" -aos)"; - const char AddFilesCmd[] = R"(a -tzip "%s" @"%s")"; - const char AddFileCmd[] = R"(a -tzip "%s" "%s")"; - const char ExtractFileCmd[] = R"(e -mmt=off "%s" "%s" %s)"; - const char ExtractFileDestination[] = R"(e -mmt=off "%s" -o"%s" "%s" %s)"; - const char ExtractOverwrite[] = "-aoa"; - const char ExtractSkipExisting[] = "-aos"; - const char ListFilesInArchiveCmd[] = R"(l -r -slt "%s")"; - - AZStd::string Get7zExePath() - { - const char* rootPath = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(rootPath, &AZ::ComponentApplicationRequests::GetEngineRoot); - AZStd::string exePath; - AzFramework::StringFunc::Path::ConstructFull(rootPath, "Tools", "7za", ".exe", exePath); - return exePath; - } - - AZStd::string GetZipExePath() - { - return Get7zExePath(); - } - - AZStd::string GetUnzipExePath() - { - return Get7zExePath(); - } - - AZStd::string GetCreateArchiveCommand(const AZStd::string& archivePath, const AZStd::string& dirToArchive) - { - return AZStd::string::format(CreateArchiveCmd, archivePath.c_str(), dirToArchive.c_str()); - } - - AZStd::string GetExtractArchiveCommand(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot) - { - if (includeRoot) - { - // Extract archive path to destinationPath\ and skipping extracting of existing files - return AZStd::string::format(ExtractArchiveCmd, archivePath.c_str(), destinationPath.c_str()); - } - else - { - // Extract archive path to destinationPath and skipping extracting of existing files - return AZStd::string::format(ExtractArchiveWithoutRootCmd, archivePath.c_str(), destinationPath.c_str()); - } - } - - AZStd::string GetAddFilesToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& listFilePath) - { - return AZStd::string::format(AddFilesCmd, archivePath.c_str(), listFilePath.c_str()); - } - - AZStd::string GetAddFileToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& file) - { - return AZStd::string::format(AddFileCmd, archivePath.c_str(), file.c_str()); - } - - AZStd::string GetExtractFileCommand(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) - { - AZStd::string commandLineArgs; - if (destinationPath.empty()) - { - // Extract file in archive from archive path to the current directory, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileCmd, archivePath.c_str(), fileInArchive.c_str(), overWrite ? ExtractOverwrite : ExtractSkipExisting); - } - else - { - // Extract file in archive from archive path to destinationPath, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileDestination, archivePath.c_str(), destinationPath.c_str(), fileInArchive.c_str(), overWrite ? ExtractOverwrite : ExtractSkipExisting); - } - - return commandLineArgs; - } - - AZStd::string GetListFilesInArchiveCommand(const AZStd::string& archivePath) - { - AZStd::string commandLineArgs = AZStd::string::format(ListFilesInArchiveCmd, archivePath.c_str()); - return commandLineArgs; - } - - /* - File output for our list archive commands takes the following two patterns for files vs directories: - - Path = basicfile2.txt - Folder = - - Size = 1 - Packed Size = 1 - Modified = 2019-03-26 18:31:10 - Created = 2019-03-26 18:31:10 - Accessed = 2019-03-26 18:31:10 - Attributes = A - Encrypted = - - Comment = - CRC = 32D70693 - Method = Store - Characteristics = NTFS - Host OS = FAT - Version = 10 - Volume Index = 0 - Offset = 44 - - Path = testfolder - Folder = + - Size = 0 - Packed Size = 0 - Modified = 2019-03-26 18:31:10 - Created = 2019-03-26 18:31:10 - Accessed = 2019-03-26 18:31:10 - Attributes = D - Encrypted = - - Comment = - CRC = - Method = Store - Characteristics = NTFS - Host OS = FAT - Version = 20 - Volume Index = 0 - Offset = 89 - - */ - - void ParseConsoleOutputFromListFilesInArchive(const AZStd::string& consoleOutput, AZStd::vector& fileEntries) - { - AZStd::vector fileEntryData; - AzFramework::StringFunc::Tokenize(consoleOutput.c_str(), fileEntryData, "\r\n"); - for (size_t slotNum = 0; slotNum < fileEntryData.size(); ++slotNum) - { - AZStd::string& line = fileEntryData[slotNum]; - if (AzFramework::StringFunc::StartsWith(line, "Path = ")) - { - if ((slotNum + 1) < fileEntryData.size()) - { - // We're checking one past each entry we find for the Folder entry and skipping anything marked as a folder - // See sample output above - if (AzFramework::StringFunc::StartsWith(fileEntryData[slotNum + 1], "Folder = -")) - { - AzFramework::StringFunc::Replace(line, "Path = ", "", false, true); - fileEntries.emplace_back(AZStd::move(line)); - slotNum++; - } - } - } - } - } - } // namespace Platform -} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake b/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake index d4fc29984c..c2c5a11c4c 100644 --- a/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake +++ b/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake @@ -7,5 +7,4 @@ # set(FILES - AzToolsFramework/Archive/ArchiveComponent_Windows.cpp ) diff --git a/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp b/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp index e7dad4b72f..66520c804c 100644 --- a/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp @@ -31,7 +31,6 @@ namespace UnitTest { namespace { - bool CreateDummyFile(const QString& fullPathToFile, const QString& tempStr = {}) { QFileInfo fi(fullPathToFile); @@ -50,7 +49,7 @@ namespace UnitTest return true; } - class ArchiveTest : + class ArchiveComponentTest : public ::testing::Test { @@ -73,7 +72,12 @@ namespace UnitTest return "Archive"; } - void CreateArchiveFolder( QString archiveFolderName, QStringList fileList ) + QString GetExtractFolderName() + { + return "Extracted"; + } + + void CreateArchiveFolder(QString archiveFolderName, QStringList fileList) { QDir tempPath = QDir(m_tempDir.GetDirectory()).filePath(archiveFolderName); @@ -84,6 +88,14 @@ namespace UnitTest } } + QString CreateArchiveListTextFile() + { + QString listFilePath = QDir(m_tempDir.GetDirectory()).absoluteFilePath("FileList.txt"); + QString textContent = CreateArchiveFileList().join("\n"); + EXPECT_TRUE(CreateDummyFile(listFilePath, textContent)); + return listFilePath; + } + void CreateArchiveFolder() { CreateArchiveFolder(GetArchiveFolderName(), CreateArchiveFileList()); @@ -99,16 +111,24 @@ namespace UnitTest return QDir(m_tempDir.GetDirectory()).filePath(GetArchiveFolderName()); } + QString GetExtractFolder() + { + return QDir(m_tempDir.GetDirectory()).filePath(GetExtractFolderName()); + } + bool CreateArchive() { - bool createResult{ false }; - AzToolsFramework::ArchiveCommandsBus::BroadcastResult(createResult, &AzToolsFramework::ArchiveCommandsBus::Events::CreateArchiveBlocking, GetArchivePath().toStdString().c_str(), GetArchiveFolder().toStdString().c_str()); - return createResult; + std::future createResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(createResult, + &AzToolsFramework::ArchiveCommandsBus::Events::CreateArchive, + GetArchivePath().toUtf8().constData(), GetArchiveFolder().toUtf8().constData()); + bool result = createResult.get(); + return result; } void SetUp() override { - m_app.reset(aznew ToolsTestApplication("ArchiveTest")); + m_app.reset(aznew ToolsTestApplication("ArchiveComponentTest")); m_app->Start(AzFramework::Application::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash @@ -132,76 +152,138 @@ namespace UnitTest }; #if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS - TEST_F(ArchiveTest, DISABLED_CreateArchiveBlocking_FilesAtThreeDepths_ArchiveCreated) + TEST_F(ArchiveComponentTest, DISABLED_CreateArchive_FilesAtThreeDepths_ArchiveCreated) #else - TEST_F(ArchiveTest, CreateArchiveBlocking_FilesAtThreeDepths_ArchiveCreated) + TEST_F(ArchiveComponentTest, CreateArchive_FilesAtThreeDepths_ArchiveCreated) #endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS { EXPECT_TRUE(m_tempDir.IsValid()); CreateArchiveFolder(); + AZ_TEST_START_TRACE_SUPPRESSION; bool createResult = CreateArchive(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; - EXPECT_EQ(createResult, true); + EXPECT_TRUE(createResult); } #if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS - TEST_F(ArchiveTest, DISABLED_ListFilesInArchiveBlocking_FilesAtThreeDepths_FilesFound) + TEST_F(ArchiveComponentTest, DISABLED_ListFilesInArchive_FilesAtThreeDepths_FilesFound) #else - TEST_F(ArchiveTest, ListFilesInArchiveBlocking_FilesAtThreeDepths_FilesFound) + TEST_F(ArchiveComponentTest, ListFilesInArchive_FilesAtThreeDepths_FilesFound) #endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS { EXPECT_TRUE(m_tempDir.IsValid()); CreateArchiveFolder(); - + + AZ_TEST_START_TRACE_SUPPRESSION; EXPECT_EQ(CreateArchive(), true); AZStd::vector fileList; bool listResult{ false }; - AzToolsFramework::ArchiveCommandsBus::BroadcastResult(listResult, &AzToolsFramework::ArchiveCommandsBus::Events::ListFilesInArchiveBlocking, GetArchivePath().toStdString().c_str(), fileList); + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(listResult, + &AzToolsFramework::ArchiveCommandsBus::Events::ListFilesInArchive, + GetArchivePath().toUtf8().constData(), fileList); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; + EXPECT_TRUE(listResult); EXPECT_EQ(fileList.size(), 6); } #if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS - TEST_F(ArchiveTest, DISABLED_CreateDeltaCatalog_AssetsNotRegistered_Failure) + TEST_F(ArchiveComponentTest, DISABLED_CreateDeltaCatalog_AssetsNotRegistered_Failure) #else - TEST_F(ArchiveTest, CreateDeltaCatalog_AssetsNotRegistered_Failure) + TEST_F(ArchiveComponentTest, CreateDeltaCatalog_AssetsNotRegistered_Failure) #endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS { QStringList fileList = CreateArchiveFileList(); CreateArchiveFolder(GetArchiveFolderName(), fileList); - + AZ_TEST_START_TRACE_SUPPRESSION; bool createResult = CreateArchive(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; EXPECT_EQ(createResult, true); bool catalogCreated{ true }; AZ::Test::AssertAbsorber assertAbsorber; - AzToolsFramework::AssetBundleCommandsBus::BroadcastResult(catalogCreated, &AzToolsFramework::AssetBundleCommandsBus::Events::CreateDeltaCatalog, GetArchivePath().toStdString().c_str(), true); + AzToolsFramework::AssetBundleCommandsBus::BroadcastResult(catalogCreated, + &AzToolsFramework::AssetBundleCommandsBus::Events::CreateDeltaCatalog, GetArchivePath().toUtf8().constData(), true); EXPECT_EQ(catalogCreated, false); } #if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS - TEST_F(ArchiveTest, DISABLED_CreateDeltaCatalog_ArchiveWithoutCatalogAssetsRegistered_Success) + TEST_F(ArchiveComponentTest, DISABLED_AddFilesToArchive_FromListFile_Success) #else - TEST_F(ArchiveTest, CreateDeltaCatalog_ArchiveWithoutCatalogAssetsRegistered_Success) + TEST_F(ArchiveComponentTest, AddFilesToArchive_FromListFile_Success) +#endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS + { + QString listFile = CreateArchiveListTextFile(); + CreateArchiveFolder(GetArchiveFolderName(), CreateArchiveFileList()); + + AZ_TEST_START_TRACE_SUPPRESSION; + std::future addResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult( + addResult, &AzToolsFramework::ArchiveCommandsBus::Events::AddFilesToArchive, GetArchivePath().toUtf8().constData(), + GetArchiveFolder().toUtf8().constData(), listFile.toUtf8().constData()); + bool result = addResult.get(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; + + EXPECT_TRUE(result); + } + +#if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS + TEST_F(ArchiveComponentTest, DISABLED_ExtractArchive_AllFiles_Success) +#else + TEST_F(ArchiveComponentTest, ExtractArchive_AllFiles_Success) +#endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS + { + CreateArchiveFolder(); + AZ_TEST_START_TRACE_SUPPRESSION; + bool createResult = CreateArchive(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; + EXPECT_TRUE(createResult); + + AZ_TEST_START_TRACE_SUPPRESSION; + std::future extractResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult( + extractResult, &AzToolsFramework::ArchiveCommandsBus::Events::ExtractArchive, GetArchivePath().toUtf8().constData(), + GetExtractFolder().toUtf8().constData()); + bool result = extractResult.get(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; + + EXPECT_TRUE(result); + + QStringList archiveFiles = CreateArchiveFileList(); + for (const auto& file : archiveFiles) + { + QString fullFilePath = QDir(GetExtractFolder()).absoluteFilePath(file); + QFileInfo fi(fullFilePath); + EXPECT_TRUE(fi.exists()); + } + } + +#if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS + TEST_F(ArchiveComponentTest, DISABLED_CreateDeltaCatalog_ArchiveWithoutCatalogAssetsRegistered_Success) +#else + TEST_F(ArchiveComponentTest, CreateDeltaCatalog_ArchiveWithoutCatalogAssetsRegistered_Success) #endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS { QStringList fileList = CreateArchiveFileList(); CreateArchiveFolder(GetArchiveFolderName(), fileList); + AZ_TEST_START_TRACE_SUPPRESSION; bool createResult = CreateArchive(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; EXPECT_EQ(createResult, true); for (const auto& thisPath : fileList) { AZ::Data::AssetInfo newInfo; - newInfo.m_relativePath = thisPath.toStdString().c_str(); + newInfo.m_relativePath = thisPath.toUtf8().constData(); newInfo.m_assetType = AZ::Uuid::CreateRandom(); newInfo.m_sizeBytes = 100; // Arbitrary AZ::Data::AssetId generatedID(AZ::Uuid::CreateRandom()); @@ -212,7 +294,7 @@ namespace UnitTest bool catalogCreated{ false }; AZ_TEST_START_TRACE_SUPPRESSION; - AzToolsFramework::AssetBundleCommandsBus::BroadcastResult(catalogCreated, &AzToolsFramework::AssetBundleCommandsBus::Events::CreateDeltaCatalog, GetArchivePath().toStdString().c_str(), true); + AzToolsFramework::AssetBundleCommandsBus::BroadcastResult(catalogCreated, &AzToolsFramework::AssetBundleCommandsBus::Events::CreateDeltaCatalog, GetArchivePath().toUtf8().constData(), true); AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // produces different counts in different platforms EXPECT_EQ(catalogCreated, true); } diff --git a/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp b/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp index 095f392501..2922cc2891 100644 --- a/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp +++ b/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp @@ -1316,7 +1316,7 @@ CarrierThread::CarrierThread(const CarrierDesc& desc, AZStd::shared_ptrGetReadablePlatformList(seed).c_str()); m_additionalSeedInfoMap[seed.m_assetId].reset(new AdditionalSeedInfo(assetInfo.m_relativePath.c_str(), platformList)); diff --git a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp index eb6cc4033c..42a43ef84e 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp @@ -411,7 +411,7 @@ bool AssetBuilderComponent::RunInResidentMode() m_running = true; m_jobThreadDesc.m_name = "Builder Job Thread"; - m_jobThread = AZStd::thread(AZStd::bind(&AssetBuilderComponent::JobThread, this), &m_jobThreadDesc); + m_jobThread = AZStd::thread(m_jobThreadDesc, AZStd::bind(&AssetBuilderComponent::JobThread, this)); AzFramework::EngineConnectionEvents::Bus::Handler::BusConnect(); // Listen for disconnects diff --git a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp index 4257457291..5d2d0e77d3 100644 --- a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp @@ -1063,10 +1063,10 @@ namespace AssetProcessor AZStd::thread_desc threadDesc; threadDesc.m_name = "AssetCatalog Thread"; - AZStd::thread catalogThread([this]() + AZStd::thread catalogThread(threadDesc, [this]() { m_data->m_assetCatalog->BuildRegistry(); - }, &threadDesc + } ); AssetNotificationMessage message("some/path/image.png", AssetNotificationMessage::NotificationType::AssetChanged, AZ::Data::AssetType::CreateRandom(), "pc"); diff --git a/Code/Tools/AssetProcessor/native/utilities/AssetServerHandler.cpp b/Code/Tools/AssetProcessor/native/utilities/AssetServerHandler.cpp index 3d87c11488..3fa4b1cacd 100644 --- a/Code/Tools/AssetProcessor/native/utilities/AssetServerHandler.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/AssetServerHandler.cpp @@ -74,8 +74,11 @@ namespace AssetProcessor AZ_TracePrintf(AssetProcessor::DebugChannel, "Extracting archive for job (%s, %s, %s) with fingerprint (%u).\n", builderParams.m_rcJob->GetJobEntry().m_pathRelativeToWatchFolder.toUtf8().data(), builderParams.m_rcJob->GetJobKey().toUtf8().data(), builderParams.m_rcJob->GetPlatformInfo().m_identifier.c_str(), builderParams.m_rcJob->GetOriginalFingerprint()); - bool success = false; - AzToolsFramework::ArchiveCommands::Bus::BroadcastResult(success, &AzToolsFramework::ArchiveCommands::ExtractArchiveBlocking, archiveAbsFilePath.toUtf8().data(), builderParams.GetTempJobDirectory(), false); + std::future extractResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(extractResult, + &AzToolsFramework::ArchiveCommandsBus::Events::ExtractArchive, + archiveAbsFilePath.toUtf8().data(), builderParams.GetTempJobDirectory()); + bool success = extractResult.get(); AZ_Error(AssetProcessor::DebugChannel, success, "Extracting archive operation failed.\n"); return success; } @@ -106,12 +109,15 @@ namespace AssetProcessor return false; } - bool success = false; - AZ_TracePrintf(AssetProcessor::DebugChannel, "Creating archive for job (%s, %s, %s) with fingerprint (%u).\n", builderParams.m_rcJob->GetJobEntry().m_pathRelativeToWatchFolder.toUtf8().data(), builderParams.m_rcJob->GetJobKey().toUtf8().data(), builderParams.m_rcJob->GetPlatformInfo().m_identifier.c_str(), builderParams.m_rcJob->GetOriginalFingerprint()); - AzToolsFramework::ArchiveCommands::Bus::BroadcastResult(success, &AzToolsFramework::ArchiveCommands::CreateArchiveBlocking, archiveAbsFilePath.toUtf8().data(), builderParams.GetTempJobDirectory()); + + std::future createResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(createResult, + &AzToolsFramework::ArchiveCommandsBus::Events::CreateArchive, + archiveAbsFilePath.toUtf8().data(), builderParams.GetTempJobDirectory()); + bool success = createResult.get(); AZ_Error(AssetProcessor::DebugChannel, success, "Creating archive operation failed. \n"); if (success && sourceFileList.size()) @@ -137,14 +143,16 @@ namespace AssetProcessor allSuccess = false; continue; } - bool success{ false }; - AzToolsFramework::ArchiveCommands::Bus::BroadcastResult(success, &AzToolsFramework::ArchiveCommands::AddFileToArchiveBlocking, archivePath.toUtf8().data(), sourceDir.path().toUtf8().data(), thisProduct.c_str()); + std::future addResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(addResult, + &AzToolsFramework::ArchiveCommandsBus::Events::AddFileToArchive, + archivePath.toUtf8().data(), sourceDir.path().toUtf8().data(), thisProduct.c_str()); + bool success = addResult.get(); if (!success) { AZ_Warning(AssetProcessor::DebugChannel, false, "Failed to add %s to %s", thisProduct.c_str(), archivePath.toUtf8().data()); allSuccess = false; } - } return allSuccess; } diff --git a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp index 0a8d9d8eb7..f0c1d765e5 100644 --- a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp +++ b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp @@ -99,7 +99,7 @@ void SRemoteThreadedObject::Start(const char* name) desc.m_name = name; auto function = AZStd::bind(&SRemoteThreadedObject::ThreadFunction, this); - m_thread = AZStd::thread(function, &desc); + m_thread = AZStd::thread(desc, function); } void SRemoteThreadedObject::WaitForThread() diff --git a/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp b/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp index a076bf3e58..61f05306be 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp @@ -26,7 +26,7 @@ namespace AZ m_workItemIndex = 0; m_lastCompletedWorkItem = AsyncWorkHandle::Null; AZStd::thread_desc threadDesc{ "AsyncWorkQueue" }; - m_thread = AZStd::thread([&]() { ProcessQueue(); }, &threadDesc); + m_thread = AZStd::thread(threadDesc, [&]() { ProcessQueue(); }); m_isInitialized = true; } diff --git a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp index b50c36d3f9..f65c36f2ed 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp @@ -43,7 +43,7 @@ namespace AZ m_isWorkQueueEmpty = true; AZStd::thread_desc threadDesc{ GetName().GetCStr() }; - m_thread = AZStd::thread([&]() { ProcessQueue(); }, &threadDesc); + m_thread = AZStd::thread(threadDesc, [&]() { ProcessQueue(); }); } return resultCode; } diff --git a/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp b/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp index d030ff8d2b..162b07406e 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp @@ -108,7 +108,7 @@ namespace AZ AZStd::thread_desc threadDesc{ "Fence WaitOnCpu Thread" }; - m_waitThread = AZStd::thread([this, callback]() + m_waitThread = AZStd::thread(threadDesc, [this, callback]() { ResultCode resultCode = WaitOnCpu(); if (resultCode != ResultCode::Success) @@ -116,7 +116,7 @@ namespace AZ AZ_Error("Fence", false, "Failed to call WaitOnCpu in async thread."); } callback(); - }, &threadDesc); + }); return ResultCode::Success; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp index 4855fbd864..36109b7b82 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp @@ -24,12 +24,11 @@ namespace AZ threadDesc.m_name = "ShaderVariantAsyncLoader"; m_serviceThread = AZStd::thread( + threadDesc, [this]() { this->ThreadServiceLoop(); - }, - &threadDesc - ); + }); } void ShaderVariantAsyncLoader::ThreadServiceLoop() diff --git a/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp b/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp index 5f3603c956..67c5325be9 100644 --- a/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp @@ -56,7 +56,7 @@ namespace Audio threadDesc.m_cpuId = AZ_TRAIT_AUDIOSYSTEM_AUDIO_THREAD_AFFINITY; auto threadFunc = AZStd::bind(&CAudioThread::Run, this); - m_thread = AZStd::thread(threadFunc, &threadDesc); + m_thread = AZStd::thread(threadDesc, threadFunc); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/BarrierInput/Code/Source/BarrierInputClient.cpp b/Gems/BarrierInput/Code/Source/BarrierInputClient.cpp index e6d5399561..ec4cbcfbd1 100644 --- a/Gems/BarrierInput/Code/Source/BarrierInputClient.cpp +++ b/Gems/BarrierInput/Code/Source/BarrierInputClient.cpp @@ -347,7 +347,7 @@ namespace BarrierInput { AZStd::thread_desc threadDesc; threadDesc.m_name = "BarrierInputClientThread"; - m_threadHandle = AZStd::thread(AZStd::bind(&BarrierClient::Run, this), &threadDesc); + m_threadHandle = AZStd::thread(threadDesc, AZStd::bind(&BarrierClient::Run, this)); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/HttpRequestor/Code/Source/HttpRequestManager.cpp b/Gems/HttpRequestor/Code/Source/HttpRequestManager.cpp index d33f37a2d7..06cf018f76 100644 --- a/Gems/HttpRequestor/Code/Source/HttpRequestManager.cpp +++ b/Gems/HttpRequestor/Code/Source/HttpRequestManager.cpp @@ -37,7 +37,7 @@ namespace HttpRequestor m_runThread = true; AWSNativeSDKInit::InitializationManager::InitAwsApi(); auto function = AZStd::bind(&Manager::ThreadFunction, this); - m_thread = AZStd::thread(function, &desc); + m_thread = AZStd::thread(desc, function); } Manager::~Manager() diff --git a/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp index 95a908b20c..631bc41358 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -155,35 +156,17 @@ namespace LevelBuilder { PopulateOptionalLevelDependencies(sourceRelativeFile, productPathDependencies); - AZStd::binary_semaphore extractionCompleteSemaphore; - auto extractResponseLambda = [&]([[maybe_unused]] bool success) { - AZStd::string levelsubfolder; - AzFramework::StringFunc::Path::Join(tempDirectory.c_str(), "level", levelsubfolder); + std::future extractResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult( + extractResult, &AzToolsFramework::ArchiveCommandsBus::Events::ExtractArchive, levelPakFile, tempDirectory); - PopulateLevelSliceDependencies(levelsubfolder, productDependencies, productPathDependencies); - PopulateMissionDependencies(levelPakFile, levelsubfolder, productPathDependencies); - PopulateLevelAudioControlDependencies(levelPakFile, productPathDependencies); + extractResult.wait(); - extractionCompleteSemaphore.release(); - }; + auto levelsubfolder = AZ::IO::Path(tempDirectory) / "level"; - AZ::Uuid handle = AZ::Uuid::Create(); - AzToolsFramework::ArchiveCommands::Bus::Broadcast( - &AzToolsFramework::ArchiveCommands::ExtractArchive, - levelPakFile, - tempDirectory, - handle, - extractResponseLambda); - - const int archiveExtractSleepMS = 20; - bool extractionCompleted = false; - while (!extractionCompleted) - { - extractionCompleted = extractionCompleteSemaphore.try_acquire_for(AZStd::chrono::milliseconds(archiveExtractSleepMS)); - // When the archive extraction is completed, the response lambda is queued on the the tick bus. - // This loop will keep executing queued events on the tickbus until the response unlocks the semaphore. - AZ::TickBus::ExecuteQueuedEvents(); - } + PopulateLevelSliceDependencies(levelsubfolder.Native(), productDependencies, productPathDependencies); + PopulateMissionDependencies(levelPakFile, levelsubfolder.Native(), productPathDependencies); + PopulateLevelAudioControlDependencies(levelPakFile, productPathDependencies); } AZStd::string GetLastFolderFromPath(const AZStd::string& path) diff --git a/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp b/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp index c182ec4f3b..e0b1f1ae36 100644 --- a/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp +++ b/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp @@ -225,7 +225,7 @@ namespace Audio AZStd::thread_desc threadDesc; threadDesc.m_name = "MicrophoneCapture-WASAPI"; auto captureFunc = AZStd::bind(&MicrophoneSystemComponentWindows::RunAudioCapture, this); - m_captureThread = AZStd::thread(captureFunc, &threadDesc); + m_captureThread = AZStd::thread(threadDesc, captureFunc); return true; } diff --git a/Gems/PhysX/Code/Tests/PhysXMultithreadingTest.cpp b/Gems/PhysX/Code/Tests/PhysXMultithreadingTest.cpp index a0013402b1..205ad4f377 100644 --- a/Gems/PhysX/Code/Tests/PhysXMultithreadingTest.cpp +++ b/Gems/PhysX/Code/Tests/PhysXMultithreadingTest.cpp @@ -119,7 +119,7 @@ namespace PhysX void Start(int waitTimeMilliseconds) { m_waitTimeMilliseconds = waitTimeMilliseconds; - m_thread = AZStd::thread(AZStd::bind(&SceneQueryBase::Tick, this), &m_threadDesc); + m_thread = AZStd::thread(m_threadDesc, AZStd::bind(&SceneQueryBase::Tick, this)); } void Join() diff --git a/Gems/SaveData/Code/Source/SaveDataSystemComponent.cpp b/Gems/SaveData/Code/Source/SaveDataSystemComponent.cpp index dad6e24abc..e92df0da68 100644 --- a/Gems/SaveData/Code/Source/SaveDataSystemComponent.cpp +++ b/Gems/SaveData/Code/Source/SaveDataSystemComponent.cpp @@ -172,14 +172,15 @@ namespace SaveData // This is safe access outside the lock guard because we only remove elements from the list // after the thread completion flag has been set to true (see also JoinAllCompletedThreads). - threadCompletionPair->m_thread = AZStd::make_unique([&threadCompleteFlag = threadCompletionPair->m_threadComplete, - dataBuffer = AZStd::move(saveDataBufferParams.dataBuffer), - dataBufferSize = saveDataBufferParams.dataBufferSize, - dataBufferName = saveDataBufferParams.dataBufferName, - onSavedCallback = saveDataBufferParams.callback, - localUserId = saveDataBufferParams.localUserId, - absoluteFilePath, - useTemporaryFile]() + threadCompletionPair->m_thread = AZStd::make_unique(saveThreadDesc, + [&threadCompleteFlag = threadCompletionPair->m_threadComplete, + dataBuffer = AZStd::move(saveDataBufferParams.dataBuffer), + dataBufferSize = saveDataBufferParams.dataBufferSize, + dataBufferName = saveDataBufferParams.dataBufferName, + onSavedCallback = saveDataBufferParams.callback, + localUserId = saveDataBufferParams.localUserId, + absoluteFilePath, + useTemporaryFile]() { SaveDataNotifications::Result result = SaveDataNotifications::Result::ErrorUnspecified; @@ -234,7 +235,7 @@ namespace SaveData // Set the thread completion flag so it will be joined in JoinAllCompletedThreads. threadCompleteFlag = true; - }, &saveThreadDesc); + }); if (waitForCompletion) { @@ -301,9 +302,10 @@ namespace SaveData // This is safe access outside the lock guard because we only remove elements from the list // after the thread completion flag has been set to true (see also JoinAllCompletedThreads). - threadCompletionPair->m_thread = AZStd::make_unique([&threadCompleteFlag = threadCompletionPair->m_threadComplete, - loadDataBufferParams, - absoluteFilePath]() + threadCompletionPair->m_thread = AZStd::make_unique(loadThreadDesc, + [&threadCompleteFlag = threadCompletionPair->m_threadComplete, + loadDataBufferParams, + absoluteFilePath]() { SaveDataNotifications::DataBuffer dataBuffer = nullptr; AZ::u64 dataBufferSize = 0; @@ -352,7 +354,7 @@ namespace SaveData // Set the thread completion flag so it will be joined in JoinAllCompletedThreads. threadCompleteFlag = true; - }, &loadThreadDesc); + }); if (waitForCompletion) { diff --git a/Tools/7za.exe b/Tools/7za.exe deleted file mode 100644 index 8a7a9ab6fb..0000000000 --- a/Tools/7za.exe +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:77613cca716edf68b9d5bab951463ed7fade5bc0ec465b36190a76299c50f117 -size 733696 diff --git a/Tools/7za_legal_notice.txt b/Tools/7za_legal_notice.txt deleted file mode 100644 index 6bcdfb1e31..0000000000 --- a/Tools/7za_legal_notice.txt +++ /dev/null @@ -1,36 +0,0 @@ -Amazon note: Source for 7-zip is hosted at -https://s3-us-west-2.amazonaws.com/ly-legal/LicenseConformance/7-zip/18.05/7z1805-src.7z - - - - 7-Zip Extra - ~~~~~~~~~~~ - License for use and distribution - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Copyright (C) 1999-2015 Igor Pavlov. - - 7-Zip Extra files are under the GNU LGPL license. - - - Notes: - You can use 7-Zip Extra on any computer, including a computer in a commercial - organization. You don't need to register or pay for 7-Zip. - - - GNU LGPL information - -------------------- - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You can receive a copy of the GNU Lesser General Public License from - http://www.gnu.org/ - From c245960c7b32b463c9b197fd6af103003f0a674b Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Fri, 1 Oct 2021 10:17:08 -0500 Subject: [PATCH 108/115] remove addition of the LoggerService as a required service Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp index 8c78ff0e73..2567d221e5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp @@ -56,7 +56,6 @@ namespace AZ void RPISystemComponent::GetRequiredServices(ComponentDescriptor::DependencyArrayType& required) { required.push_back(RHI::Factory::GetComponentService()); - required.push_back(AZ_CRC_CE("LoggerService")); } void RPISystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) From bf393ec85c62129de801d0e65d5a968bb99d0133 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 1 Oct 2021 08:38:46 -0700 Subject: [PATCH 109/115] fixes some install paths issues in monolithic release (#4422) * fixes some install paths issues in monolithic release Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * PR comments Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/LauncherUnified/launcher_generator.cmake | 17 ++--- Code/Legacy/CryCommon/ProjectDefines.h | 3 - Code/Legacy/CryCommon/platform_impl.cpp | 3 - Registry/CMakeLists.txt | 4 +- cmake/Packaging.cmake | 70 +++++++++++-------- cmake/Platform/Common/Install_common.cmake | 15 ++++ .../Platform/Windows/Packaging_windows.cmake | 1 + cmake/Projects.cmake | 20 ++++-- 8 files changed, 76 insertions(+), 57 deletions(-) diff --git a/Code/LauncherUnified/launcher_generator.cmake b/Code/LauncherUnified/launcher_generator.cmake index b30f752c85..5c9ee68e27 100644 --- a/Code/LauncherUnified/launcher_generator.cmake +++ b/Code/LauncherUnified/launcher_generator.cmake @@ -19,19 +19,10 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC # Otherwise the the absolute project_path is returned with symlinks resolved file(REAL_PATH ${project_path} project_real_path BASE_DIRECTORY ${LY_ROOT_FOLDER}) if(NOT project_name) - if(NOT EXISTS ${project_real_path}/project.json) - message(FATAL_ERROR "The specified project path of ${project_real_path} does not contain a project.json file") - else() - # Add the project_name to global LY_PROJECTS_TARGET_NAME property - ly_file_read("${project_real_path}/project.json" project_json) - string(JSON project_name ERROR_VARIABLE json_error GET ${project_json} "project_name") - if(json_error) - message(FATAL_ERROR "There is an error reading the \"project_name\" key from the '${project_real_path}/project.json' file: ${json_error}") - endif() - message(WARNING "The project located at path ${project_real_path} has a valid \"project name\" of '${project_name}' read from it's project.json file." - " This indicates that the ${project_real_path}/CMakeLists.txt is not properly appending the \"project name\" " - "to the LY_PROJECTS_TARGET_NAME global property. Other configuration errors might occur") - endif() + o3de_read_json_key(project_name ${project_real_path}/project.json "project_name") + message(WARNING "The project located at path ${project_real_path} has a valid \"project name\" of '${project_name}' read from it's project.json file." + " This indicates that the ${project_real_path}/CMakeLists.txt is not properly appending the \"project name\" " + "to the LY_PROJECTS_TARGET_NAME global property. Other configuration errors might occur") endif() ################################################################################ diff --git a/Code/Legacy/CryCommon/ProjectDefines.h b/Code/Legacy/CryCommon/ProjectDefines.h index 203bd304c9..2c3df4e37f 100644 --- a/Code/Legacy/CryCommon/ProjectDefines.h +++ b/Code/Legacy/CryCommon/ProjectDefines.h @@ -81,9 +81,6 @@ #include AZ_RESTRICTED_FILE(ProjectDefines_h) #else #define PROJECTDEFINES_H_TRAIT_DISABLE_MONOLITHIC_PROFILING_MARKERS 1 - #if !defined(LINUX) && !defined(APPLE) - #define PROJECTDEFINES_H_TRAIT_ENABLE_SOFTCODE_SYSTEM 1 - #endif #if defined(WIN32) || defined(WIN64) || defined(LINUX) || defined(APPLE) #define PROJECTDEFINES_H_TRAIT_USE_GPU_PARTICLES 1 #endif diff --git a/Code/Legacy/CryCommon/platform_impl.cpp b/Code/Legacy/CryCommon/platform_impl.cpp index 323d3daf65..a68a5150db 100644 --- a/Code/Legacy/CryCommon/platform_impl.cpp +++ b/Code/Legacy/CryCommon/platform_impl.cpp @@ -71,7 +71,6 @@ void InitCRTHandlers() void InitCRTHandlers() {} #endif -#ifndef SOFTCODE ////////////////////////////////////////////////////////////////////////// // This is an entry to DLL initialization function that must be called for each loaded module ////////////////////////////////////////////////////////////////////////// @@ -136,8 +135,6 @@ void* GetDetachEnvironmentSymbol() return reinterpret_cast(&DetachEnvironment); } -#endif // !defined(SOFTCODE) - bool g_bProfilerEnabled = false; ////////////////////////////////////////////////////////////////////////// diff --git a/Registry/CMakeLists.txt b/Registry/CMakeLists.txt index 100867010d..773adac07f 100644 --- a/Registry/CMakeLists.txt +++ b/Registry/CMakeLists.txt @@ -12,8 +12,6 @@ endif() ly_install_directory(DIRECTORIES .) -cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory) - ly_install_directory(DIRECTORIES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/Registry - DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$ + DESTINATION ${runtime_output_directory} ) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 477a5f24ea..006689549b 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -89,37 +89,49 @@ endif() set(_cmake_package_dest ${CPACK_BINARY_DIR}/${CPACK_CMAKE_PACKAGE_FILE}) -string(REPLACE "." ";" _version_componets "${CPACK_DESIRED_CMAKE_VERSION}") -list(GET _version_componets 0 _major_version) -list(GET _version_componets 1 _minor_version) - -set(_url_version_tag "v${_major_version}.${_minor_version}") -set(_package_url "https://cmake.org/files/${_url_version_tag}/${CPACK_CMAKE_PACKAGE_FILE}") - -message(STATUS "Downloading CMake ${CPACK_DESIRED_CMAKE_VERSION} for packaging...") -download_file( - URL ${_package_url} - TARGET_FILE ${_cmake_package_dest} - EXPECTED_HASH ${CPACK_CMAKE_PACKAGE_HASH} - RESULTS _results -) -list(GET _results 0 _status_code) - -if (${_status_code} EQUAL 0 AND EXISTS ${_cmake_package_dest}) - message(STATUS "Package found and verified!") -else() - file(REMOVE ${_cmake_package_dest}) - list(REMOVE_AT _results 0) - - set(_error_message "An error occurred, code ${_status_code}. URL ${_package_url} - ${_results}") - - if(${_status_code} EQUAL 1) - string(APPEND _error_message - " Please double check the CPACK_CMAKE_PACKAGE_FILE and " - "CPACK_CMAKE_PACKAGE_HASH properties before trying again.") +if(EXISTS ${_cmake_package_dest}) + file(SHA256 ${_cmake_package_dest} hash_of_downloaded_file) + if (NOT "${hash_of_downloaded_file}" STREQUAL "${CPACK_CMAKE_PACKAGE_HASH}") + message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found at ${_cmake_package_dest} but expected hash missmatches, re-downloading...") + file(REMOVE ${_cmake_package_dest}) + else() + message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found") endif() +endif() +if(NOT EXISTS ${_cmake_package_dest}) + # download it + string(REPLACE "." ";" _version_componets "${CPACK_DESIRED_CMAKE_VERSION}") + list(GET _version_componets 0 _major_version) + list(GET _version_componets 1 _minor_version) - message(FATAL_ERROR ${_error_message}) + set(_url_version_tag "v${_major_version}.${_minor_version}") + set(_package_url "https://cmake.org/files/${_url_version_tag}/${CPACK_CMAKE_PACKAGE_FILE}") + + message(STATUS "Downloading CMake ${CPACK_DESIRED_CMAKE_VERSION} for packaging...") + download_file( + URL ${_package_url} + TARGET_FILE ${_cmake_package_dest} + EXPECTED_HASH ${CPACK_CMAKE_PACKAGE_HASH} + RESULTS _results + ) + list(GET _results 0 _status_code) + + if (${_status_code} EQUAL 0 AND EXISTS ${_cmake_package_dest}) + message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found") + else() + file(REMOVE ${_cmake_package_dest}) + list(REMOVE_AT _results 0) + + set(_error_message "An error occurred, code ${_status_code}. URL ${_package_url} - ${_results}") + + if(${_status_code} EQUAL 1) + string(APPEND _error_message + " Please double check the CPACK_CMAKE_PACKAGE_FILE and " + "CPACK_CMAKE_PACKAGE_HASH properties before trying again.") + endif() + + message(FATAL_ERROR ${_error_message}) + endif() endif() install(FILES ${_cmake_package_dest} diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 8fb2effe29..5fa7f21939 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -430,6 +430,21 @@ function(ly_setup_cmake_install) DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + string(CONFIGURE [=[ +if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") + set(install_output_folder "${CMAKE_INSTALL_PREFIX}/@runtime_output_directory@") + file(WRITE ${install_output_folder}/engine.json +"{ + \"engine_name\": \"@LY_VERSION_ENGINE_NAME@\" +}") +endif() +]=] + install_engine_json_release + @ONLY + ) + install(CODE ${install_engine_json_release} + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being + ) # Collect all Find files that were added with ly_add_external_target_path unset(additional_find_files) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index ced7757852..4a03df2fd2 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -23,6 +23,7 @@ set(CPACK_WIX_ROOT ${LY_INSTALLER_WIX_ROOT}) set(CPACK_GENERATOR WIX) +set(CPACK_THREADS 0) set(_cmake_package_name "cmake-${CPACK_DESIRED_CMAKE_VERSION}-windows-x86_64") set(CPACK_CMAKE_PACKAGE_FILE "${_cmake_package_name}.zip") set(CPACK_CMAKE_PACKAGE_HASH "15a49e2ab81c1822d75b1b1a92f7863f58e31f6d6aac1c4103eef2b071be3112") diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 61cb101909..b21704ee85 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -10,7 +10,7 @@ include_guard() -set(LY_PROJECTS "${LY_PROJECTS}" CACHE STRING "List of projects to enable, this can be a relative path to the engine root or an absolute path") +set(LY_PROJECTS "" CACHE STRING "List of projects to enable, this can be a relative path to the engine root or an absolute path") #! ly_add_target_dependencies: adds module load dependencies for this target. # @@ -143,21 +143,25 @@ foreach(project ${LY_PROJECTS}) ly_generate_project_build_path_setreg(${full_directory_path}) add_project_json_external_subdirectories(${full_directory_path}) + # Get project name + o3de_read_json_key(project_name ${full_directory_path}/project.json "project_name") + # Generate pak for project in release installs - cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory) + cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE install_base_runtime_output_directory) set(install_engine_pak_template [=[ if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") - set(install_output_folder "${CMAKE_INSTALL_PREFIX}/@runtime_output_directory@/@PAL_PLATFORM_NAME@/${CMAKE_INSTALL_CONFIG_NAME}/@LY_BUILD_PERMUTATION@") + set(install_output_folder "${CMAKE_INSTALL_PREFIX}/@install_base_runtime_output_directory@/@PAL_PLATFORM_NAME@/${CMAKE_INSTALL_CONFIG_NAME}/@LY_BUILD_PERMUTATION@") + set(install_pak_output_folder "${install_output_folder}/Cache/@LY_ASSET_DEPLOY_ASSET_TYPE@") if(NOT DEFINED LY_ASSET_DEPLOY_ASSET_TYPE) set(LY_ASSET_DEPLOY_ASSET_TYPE @LY_ASSET_DEPLOY_ASSET_TYPE@) endif() - message(STATUS "Generating ${install_output_folder}/engine.pak from @full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") - file(MAKE_DIRECTORY "${install_output_folder}") + message(STATUS "Generating ${install_pak_output_folder}/engine.pak from @full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") + file(MAKE_DIRECTORY "${install_pak_output_folder}") cmake_path(SET cache_product_path "@full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") file(GLOB product_assets "${cache_product_path}/*") if(product_assets) execute_process( - COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_output_folder}/engine.pak" --format=zip -- ${product_assets} + COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_pak_output_folder}/engine.pak" --format=zip -- ${product_assets} WORKING_DIRECTORY "${cache_product_path}" RESULT_VARIABLE archive_creation_result ) @@ -165,6 +169,10 @@ if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") message(STATUS "${install_output_folder}/engine.pak generated") endif() endif() + file(WRITE ${install_output_folder}/project.json +"{ + \"project_name\": \"@project_name@\" +}") endif() ]=]) string(CONFIGURE "${install_engine_pak_template}" install_engine_pak_code @ONLY) From b984335b302e55e67baf1f9ea3ce14dd7e238187 Mon Sep 17 00:00:00 2001 From: SJ Date: Fri, 1 Oct 2021 09:02:09 -0700 Subject: [PATCH 110/115] [Android] Fix black screen on Android when app is launched (#4418) * When copying the runtime dependency setreg files to the cache, the name of the registry directory should be all lower case Signed-off-by: amzn-sj * Lower case the registry folder name when looking in the asset cache. Signed-off-by: amzn-sj --- .../Settings/SettingsRegistryMergeUtils.cpp | 4 ++- .../Tools/Platform/Android/android_support.py | 26 +++++++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index da7110e36e..113fdd433e 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -717,7 +717,9 @@ namespace AZ::SettingsRegistryMergeUtils if (registry.Get(cacheRootPath, FilePathKey_CacheRootFolder)) { mergePath = AZStd::move(cacheRootPath); - mergePath /= SettingsRegistryInterface::RegistryFolder; + AZStd::fixed_string<32> registryFolderLower(SettingsRegistryInterface::RegistryFolder); + AZStd::to_lower(registryFolderLower.begin(), registryFolderLower.end()); + mergePath /= registryFolderLower; registry.MergeSettingsFolder(mergePath.Native(), specializations, platform, "", scratchBuffer); } diff --git a/cmake/Tools/Platform/Android/android_support.py b/cmake/Tools/Platform/Android/android_support.py index 77c8a37a35..54f1a4c8f4 100755 --- a/cmake/Tools/Platform/Android/android_support.py +++ b/cmake/Tools/Platform/Android/android_support.py @@ -381,6 +381,23 @@ CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_DEPENDENCY_FORMAT_STR = """ }} """ +CUSTOM_GRADLE_COPY_REGISTRY_FOLDER_FORMAT_STR = """ + task copyRegistryFolder{config}(type: Copy) {{ + from ('build/intermediates/cmake/{config_lower}/obj/arm64-v8a/{config_lower}/Registry') + into ('{asset_layout_folder}/registry') + include ('*.setreg') + }} + + compile{config}Sources.dependsOn copyRegistryFolder{config} +""" + +CUSTOM_GRADLE_COPY_REGISTRY_FOLDER_DEPENDENCY_FORMAT_STR = """ + + copyRegistryFolder{config}.mustRunAfter {{ + tasks.findAll {{ task->task.name.contains('syncLYLayoutMode{config}') }} + }} +""" + CUSTOM_APPLY_ASSET_LAYOUT_TASK_FORMAT_STR = """ task syncLYLayoutMode{config}(type:Exec) {{ workingDir '{working_dir}' @@ -851,14 +868,13 @@ class AndroidProjectGenerator(object): config=native_config) # Copy over settings registry files from the Registry folder with build output directory gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] += \ - CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_FORMAT_STR.format(config=native_config, - config_lower=native_config_lower, - asset_layout_folder=(self.build_dir / 'app/src/main/assets').resolve().as_posix(), - file_includes='**/Registry/*.setreg') + CUSTOM_GRADLE_COPY_REGISTRY_FOLDER_FORMAT_STR.format(config=native_config, + config_lower=native_config_lower, + asset_layout_folder=(self.build_dir / 'app/src/main/assets').resolve().as_posix()) if self.include_assets_in_apk: # This is a dependency of the layout sync only if we are including assets in the APK gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] += \ - CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_DEPENDENCY_FORMAT_STR.format(config=native_config) + CUSTOM_GRADLE_COPY_REGISTRY_FOLDER_DEPENDENCY_FORMAT_STR.format(config=native_config) From 23322edde7e138e4466e5f9de739b682c0621a65 Mon Sep 17 00:00:00 2001 From: chiyenteng <82238204+chiyenteng@users.noreply.github.com> Date: Fri, 1 Oct 2021 10:02:00 -0700 Subject: [PATCH 111/115] Fix Entity id consistency issue & refactor prefab workflows/tests (#4373) * Fix Entity id consistency issue & refactor prefab workflows/test framework Signed-off-by: chiyteng * Update comments Signed-off-by: chiyteng * Modify CreatePrefab and remove extra spaces Signed-off-by: chiyteng * Address comments Signed-off-by: chiyteng * Refactor prefab instance constructors Signed-off-by: chiyteng * Remove commented out code Signed-off-by: chiyteng --- .../Gem/PythonTests/prefab/Prefab.py | 117 +++++++++--------- ...fab_BasicWorkflow_CreateAndDeletePrefab.py | 3 +- ...b_BasicWorkflow_CreateAndReparentPrefab.py | 6 +- .../Prefab_BasicWorkflow_InstantiatePrefab.py | 4 +- .../PythonTests/prefab/Prefab_Test_Utils.py | 16 +-- .../PrefabEditorEntityOwnershipService.cpp | 38 +++--- .../Prefab/Instance/Instance.cpp | 64 +++++++--- .../Prefab/Instance/Instance.h | 10 +- .../Instance/TemplateInstanceMapper.cpp | 8 +- .../Prefab/Instance/TemplateInstanceMapper.h | 6 +- .../TemplateInstanceMapperInterface.h | 2 +- .../AzToolsFramework/Prefab/Link/Link.cpp | 4 +- .../AzToolsFramework/Prefab/Link/Link.h | 4 +- .../Prefab/PrefabSystemComponent.cpp | 50 ++++---- .../Prefab/PrefabSystemComponent.h | 62 ++++++---- .../Prefab/PrefabSystemComponentInterface.h | 21 ++-- .../AzToolsFramework/Prefab/PrefabUndo.cpp | 6 +- .../AzToolsFramework/Prefab/PrefabUndo.h | 6 +- .../Benchmark/PrefabCreateBenchmarks.cpp | 4 +- .../PrefabUpdateInstancesBenchmarks.cpp | 8 +- .../Prefab/PrefabFocus/PrefabFocusTests.cpp | 2 +- ...refabInstanceToTemplatePropagatorTests.cpp | 2 +- .../Tests/Prefab/PrefabInstantiateTests.cpp | 4 +- .../Tests/Prefab/PrefabTestDataUtils.cpp | 4 +- .../Tests/Prefab/PrefabTestDataUtils.h | 4 +- .../Tests/Prefab/PrefabTestDomUtils.cpp | 6 +- .../Tests/Prefab/PrefabTestDomUtils.h | 6 +- .../Tests/Prefab/PrefabTestUndoFixture.cpp | 4 +- .../Prefab/PrefabUpdateInstancesTests.cpp | 4 +- .../Prefab/PrefabUpdateTemplateTests.cpp | 28 ++--- .../Prefab/PrefabUpdateWithPatchesTests.cpp | 2 +- .../SerializeContextTools/SliceConverter.cpp | 4 +- 32 files changed, 284 insertions(+), 225 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py index 14a1ab62f0..9b4d2d1393 100644 --- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py +++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py @@ -25,28 +25,39 @@ import prefab.Prefab_Test_Utils as prefab_test_utils # This is a helper class which contains some of the useful information about a prefab instance. class PrefabInstance: - def __init__(self, name: str=None, prefab_file_name: str=None, container_entity: EditorEntity=EntityId()): - self.name = name + def __init__(self, prefab_file_name: str=None, container_entity: EditorEntity=EntityId()): self.prefab_file_name: str = prefab_file_name self.container_entity: EditorEntity = container_entity + def __eq__(self, other): + return other and self.container_entity.id == other.container_entity.id + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.container_entity.id) + """ See if this instance is valid to be used with other prefab operations. :return: Whether the target instance is valid or not. """ def is_valid() -> bool: - return self.container_entity.id.IsValid() and self.name is not None and self.prefab_file_name in Prefab.existing_prefabs + return self.container_entity.id.IsValid() and self.prefab_file_name in Prefab.existing_prefabs - """ Reparent this instance to target parent entity. The function will also check pop up dialog ui in editor to see if there's prefab cyclical dependency error while reparenting prefabs. :param parent_entity_id: The id of the entity this instance should be a child of in the transform hierarchy next. """ async def ui_reparent_prefab_instance(self, parent_entity_id: EntityId): - container_entity_name = self.container_entity.get_name() - current_children_entity_ids_having_prefab_name = prefab_test_utils.get_children_ids_by_name(parent_entity_id, container_entity_name) - Report.info(f'current_children_entity_ids_having_prefab_name: {current_children_entity_ids_having_prefab_name}') + container_entity_id_before_reparent = self.container_entity.id + + original_parent = EditorEntity(self.container_entity.get_parent_id()) + original_parent_before_reparent_children_ids = set(original_parent.get_children_ids()) + + new_parent = EditorEntity(parent_entity_id) + new_parent_before_reparent_children_ids = set(new_parent.get_children_ids()) pyside_utils.run_soon(lambda: self.container_entity.set_parent_entity(parent_entity_id)) pyside_utils.run_soon(lambda: prefab_test_utils.wait_for_propagation()) @@ -60,18 +71,23 @@ class PrefabInstance: except pyside_utils.EventLoopTimeoutException: pass - updated_children_entity_ids_having_prefab_name = prefab_test_utils.get_children_ids_by_name(parent_entity_id, container_entity_name) - Report.info(f'updated_children_entity_ids_having_prefab_name: {updated_children_entity_ids_having_prefab_name}') - new_child_with_reparented_prefab_name_added = len(updated_children_entity_ids_having_prefab_name) == len(current_children_entity_ids_having_prefab_name) + 1 - assert new_child_with_reparented_prefab_name_added, "No entity with reparented prefab name become a child of target parent entity" + original_parent_after_reparent_children_ids = set(original_parent.get_children_ids()) + assert len(original_parent_after_reparent_children_ids) == len(original_parent_before_reparent_children_ids) - 1, \ + "The children count of the Prefab Instance's original parent should be decreased by 1." + assert not container_entity_id_before_reparent in original_parent_after_reparent_children_ids, \ + "This Prefab Instance is still a child entity of its original parent entity." + + new_parent_after_reparent_children_ids = set(new_parent.get_children_ids()) + assert len(new_parent_after_reparent_children_ids) == len(new_parent_before_reparent_children_ids) + 1, \ + "The children count of the Prefab Instance's new parent should be increased by 1." - updated_container_entity_id = set(updated_children_entity_ids_having_prefab_name).difference(current_children_entity_ids_having_prefab_name).pop() - updated_container_entity = EditorEntity(updated_container_entity_id) - updated_container_entity_parent_id = updated_container_entity.get_parent_id() - has_correct_parent = updated_container_entity_parent_id.ToString() == parent_entity_id.ToString() - assert has_correct_parent, "Prefab reparented is *not* under the expected parent entity" + container_entity_id_after_reparent = set(new_parent_after_reparent_children_ids).difference(new_parent_before_reparent_children_ids).pop() + reparented_container_entity = EditorEntity(container_entity_id_after_reparent) + reparented_container_entity_parent_id = reparented_container_entity.get_parent_id() + has_correct_parent = reparented_container_entity_parent_id.ToString() == parent_entity_id.ToString() + assert has_correct_parent, "Prefab Instance reparented is *not* under the expected parent entity" - self.container_entity = EditorEntity(updated_container_entity_id) + self.container_entity = reparented_container_entity # This is a helper class which contains some of the useful information about a prefab template. class Prefab: @@ -81,7 +97,7 @@ class Prefab: def __init__(self, file_name: str): self.file_name:str = file_name self.file_path: str = prefab_test_utils.get_prefab_file_path(file_name) - self.instances: dict = {} + self.instances: set[PrefabInstance] = set() """ Check if a prefab is ready to be used to generate its instances. @@ -122,10 +138,10 @@ class Prefab: :param entities: The entities that should form the new prefab (along with their descendants). :param file_name: A unique file name of new prefab. :param prefab_instance_name: A name for the very first instance generated while prefab creation. The default instance name is the same as file_name. - :return: An outcome object with an entityId of the new prefab's container entity; on failure, it comes with an error message detailing the cause of the error. + :return: Created Prefab object and the very first PrefabInstance object owned by the prefab. """ @classmethod - def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> Prefab: + def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> (Prefab, PrefabInstance): assert not Prefab.is_prefab_loaded(file_name), f"Can't create Prefab '{file_name}' since the prefab already exists" new_prefab = Prefab(file_name) @@ -133,18 +149,18 @@ class Prefab: create_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'CreatePrefabInMemory', entity_ids, new_prefab.file_path) assert create_prefab_result.IsSuccess(), f"Prefab operation 'CreatePrefab' failed. Error: {create_prefab_result.GetError()}" - container_entity = EditorEntity(create_prefab_result.GetValue()) + container_entity_id = create_prefab_result.GetValue() + container_entity = EditorEntity(container_entity_id) if prefab_instance_name: container_entity.set_name(prefab_instance_name) - else: - prefab_instance_name = file_name prefab_test_utils.wait_for_propagation() - container_entity_id = prefab_test_utils.find_entity_by_unique_name(prefab_instance_name) - new_prefab.instances[prefab_instance_name] = PrefabInstance(prefab_instance_name, file_name, EditorEntity(container_entity_id)) + + new_prefab_instance = PrefabInstance(file_name, EditorEntity(container_entity_id)) + new_prefab.instances.add(new_prefab_instance) Prefab.existing_prefabs[file_name] = new_prefab - return new_prefab + return new_prefab, new_prefab_instance """ Remove target prefab instances. @@ -152,22 +168,15 @@ class Prefab: """ @classmethod def remove_prefabs(cls, prefab_instances: list[PrefabInstance]): - instances_to_remove_name_counts = Counter() - instances_removed_expected_name_counts = Counter() - - entities_to_remove = [prefab_instance.container_entity for prefab_instance in prefab_instances] - while entities_to_remove: - entity = entities_to_remove.pop(-1) - entity_name = entity.get_name() - instances_to_remove_name_counts[entity_name] += 1 - + entity_ids_to_remove = [] + entity_id_queue = [prefab_instance.container_entity for prefab_instance in prefab_instances] + while entity_id_queue: + entity = entity_id_queue.pop(0) children_entity_ids = entity.get_children_ids() for child_entity_id in children_entity_ids: - entities_to_remove.append(EditorEntity(child_entity_id)) + entity_id_queue.append(EditorEntity(child_entity_id)) - for entity_name, entity_count in instances_to_remove_name_counts.items(): - entities = prefab_test_utils.find_entities_by_name(entity_name) - instances_removed_expected_name_counts[entity_name] = len(entities) - entity_count + entity_ids_to_remove.append(entity.id) container_entity_ids = [prefab_instance.container_entity.id for prefab_instance in prefab_instances] delete_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'DeleteEntitiesAndAllDescendantsInInstance', container_entity_ids) @@ -175,28 +184,24 @@ class Prefab: prefab_test_utils.wait_for_propagation() - prefab_entities_deleted = True - for entity_name, expected_entity_count in instances_removed_expected_name_counts.items(): - actual_entity_count = len(prefab_test_utils.find_entities_by_name(entity_name)) - if actual_entity_count is not expected_entity_count: - prefab_entities_deleted = False - break - - assert prefab_entities_deleted, "Not all entities and descendants in target prefabs are deleted." + entity_ids_after_delete = set(prefab_test_utils.get_all_entities()) + for entity_id_removed in entity_ids_to_remove: + if entity_id_removed in entity_ids_after_delete: + assert prefab_entities_deleted, "Not all entities and descendants in target prefabs are deleted." for instance in prefab_instances: instance_deleted_prefab = Prefab.get_prefab(instance.prefab_file_name) - instance_deleted_prefab.instances.pop(instance.name) + instance_deleted_prefab.instances.remove(instance) instance = PrefabInstance() """ Instantiate an instance of this prefab. - :param name: A name for newly instantiated prefab instance. The default instance name is the same as this prefab's file name. :param parent_entity: The entity the prefab should be a child of in the transform hierarchy. + :param name: A name for newly instantiated prefab instance. The default instance name is the same as this prefab's file name. :param prefab_position: The position in world space the prefab should be instantiated in. - :return: An outcome object with an entityId of the new prefab's container entity; on failure, it comes with an error message detailing the cause of the error. + :return: Instantiated PrefabInstance object owned by this prefab. """ - def instantiate(self, name: str=None, parent_entity: EditorEntity=None, prefab_position: Vector3=Vector3()) -> PrefabInstance: + def instantiate(self, parent_entity: EditorEntity=None, name: str=None, prefab_position: Vector3=Vector3()) -> PrefabInstance: parent_entity_id = parent_entity.id if parent_entity is not None else EntityId() instantiate_prefab_result = prefab.PrefabPublicRequestBus( @@ -209,13 +214,13 @@ class Prefab: if name: container_entity.set_name(name) - else: - name = self.file_name prefab_test_utils.wait_for_propagation() - container_entity_id = prefab_test_utils.find_entity_by_unique_name(name) - self.instances[name] = PrefabInstance(name, self.file_name, EditorEntity(container_entity_id)) + + new_prefab_instance = PrefabInstance(self.file_name, EditorEntity(container_entity_id)) + assert not new_prefab_instance in self.instances, "This prefab instance is already existed before this instantiation." + self.instances.add(new_prefab_instance) prefab_test_utils.check_entity_at_position(container_entity_id, prefab_position) - return container_entity_id + return new_prefab_instance diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py index c6e0daa4dd..f3fbcfa6ad 100644 --- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py +++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py @@ -22,11 +22,10 @@ def Prefab_BasicWorkflow_CreateAndDeletePrefab(): car_prefab_entities = [car_entity] # Checks for prefab creation passed or not - car_prefab = Prefab.create_prefab( + _, car = Prefab.create_prefab( car_prefab_entities, CAR_PREFAB_FILE_NAME) # Checks for prefab deletion passed or not - car = car_prefab.instances[CAR_PREFAB_FILE_NAME] Prefab.remove_prefabs([car]) if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py index 04f7b97628..e5a9d9930a 100644 --- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py +++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py @@ -28,7 +28,7 @@ def Prefab_BasicWorkflow_CreateAndReparentPrefab(): car_prefab_entities = [car_entity] # Checks for prefab creation passed or not - car_prefab = Prefab.create_prefab( + _, car = Prefab.create_prefab( car_prefab_entities, CAR_PREFAB_FILE_NAME) # Creates another new Entity at the root level @@ -36,12 +36,10 @@ def Prefab_BasicWorkflow_CreateAndReparentPrefab(): wheel_prefab_entities = [wheel_entity] # Checks for wheel prefab creation passed or not - wheel_prefab = Prefab.create_prefab( + _, wheel = Prefab.create_prefab( wheel_prefab_entities, WHEEL_PREFAB_FILE_NAME) # Checks for prefab reparenting passed or not - car = car_prefab.instances[CAR_PREFAB_FILE_NAME] - wheel = wheel_prefab.instances[WHEEL_PREFAB_FILE_NAME] await wheel.ui_reparent_prefab_instance(car.container_entity.id) run_test() diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py index b9015ab556..46be669697 100644 --- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py +++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py @@ -22,11 +22,11 @@ def Prefab_BasicWorkflow_InstantiatePrefab(): # Checks for prefab instantiation passed or not test_prefab = Prefab.get_prefab(EXISTING_TEST_PREFAB_FILE_NAME) - instantiated_test_container_entity_id = test_prefab.instantiate( + test_instance = test_prefab.instantiate( prefab_position=INSTANTIATED_TEST_PREFAB_POSITION) prefab_test_utils.check_entity_children_count( - instantiated_test_container_entity_id, + test_instance.container_entity.id, EXPECTED_TEST_PREFAB_CHILDREN_COUNT) if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py index 8cd59ed077..3e19911449 100644 --- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py +++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py @@ -29,20 +29,8 @@ def find_entities_by_name(entity_name): searchFilter.names = [entity_name] return entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter) -def find_entity_by_unique_name(entity_name): - unique_name_entity_found_result = ( - "Entity with a unique name found", - "Entity with a unique name *not* found") - - entities = find_entities_by_name(entity_name) - unique_name_entity_found = len(entities) == 1 - Report.result(unique_name_entity_found_result, unique_name_entity_found) - - if unique_name_entity_found: - return entities[0] - else: - Report.info(f"{len(entities)} entities with name '{entity_name}' found") - return EntityId() +def get_all_entities(): + return entity.SearchBus(bus.Broadcast, 'SearchEntities', entity.SearchFilter()) def check_entity_at_position(entity_id, expected_entity_position): entity_at_expected_position_result = ( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp index e5daf2674d..7db507e751 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp @@ -18,8 +18,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -317,17 +318,18 @@ namespace AzToolsFramework const AZStd::vector& entities, AZStd::vector>&& nestedPrefabInstances, AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder) { - AZStd::unique_ptr createdPrefabInstance = - m_prefabSystemComponent->CreatePrefab(entities, AZStd::move(nestedPrefabInstances), filePath, nullptr, false); + if (!instanceToParentUnder) + { + instanceToParentUnder = *m_rootInstance; + } + + AZStd::unique_ptr createdPrefabInstance = m_prefabSystemComponent->CreatePrefab( + entities, AZStd::move(nestedPrefabInstances), filePath, nullptr, instanceToParentUnder, false); if (createdPrefabInstance) { - if (!instanceToParentUnder) - { - instanceToParentUnder = *m_rootInstance; - } - - Prefab::Instance& addedInstance = instanceToParentUnder->get().AddInstance(AZStd::move(createdPrefabInstance)); + Prefab::Instance& addedInstance = instanceToParentUnder->get().AddInstance( + AZStd::move(createdPrefabInstance)); AZ::Entity* containerEntity = addedInstance.m_containerEntity.get(); containerEntity->AddComponent(aznew Prefab::EditorPrefabComponent()); HandleEntitiesAdded({containerEntity}); @@ -341,16 +343,18 @@ namespace AzToolsFramework Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::InstantiatePrefab( AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder) { - AZStd::unique_ptr createdPrefabInstance = m_prefabSystemComponent->InstantiatePrefab(filePath); - - if (createdPrefabInstance) + if (!instanceToParentUnder) { - if (!instanceToParentUnder) - { - instanceToParentUnder = *m_rootInstance; - } + instanceToParentUnder = *m_rootInstance; + } - Prefab::Instance& addedInstance = instanceToParentUnder->get().AddInstance(AZStd::move(createdPrefabInstance)); + AZStd::unique_ptr instantiatedPrefabInstance = + m_prefabSystemComponent->InstantiatePrefab(filePath, instanceToParentUnder); + + if (instantiatedPrefabInstance) + { + Prefab::Instance& addedInstance = instanceToParentUnder->get().AddInstance( + AZStd::move(instantiatedPrefabInstance)); HandleEntitiesAdded({addedInstance.m_containerEntity.get()}); return addedInstance; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp index 54e7f7608c..b5db46d0db 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -28,24 +29,52 @@ namespace AzToolsFramework } Instance::Instance(AZStd::unique_ptr containerEntity) + : Instance(AZStd::move(containerEntity), AZStd::nullopt, GenerateInstanceAlias()) { - m_instanceEntityMapper = AZ::Interface::Get(); + } + Instance::Instance(InstanceOptionalReference parent) + : Instance(nullptr, parent, GenerateInstanceAlias()) + { + } + + Instance::Instance(InstanceAlias alias) + : Instance(nullptr, AZStd::nullopt, AZStd::move(alias)) + { + } + + Instance::Instance(AZStd::unique_ptr containerEntity, InstanceOptionalReference parent) + : Instance(AZStd::move(containerEntity), parent, GenerateInstanceAlias()) + { + } + + Instance::Instance(AZStd::unique_ptr containerEntity, InstanceOptionalReference parent, InstanceAlias alias) + : m_parent(parent.has_value() ? &parent->get() : nullptr) + , m_alias(AZStd::move(alias)) + , m_containerEntity(containerEntity ? AZStd::move(containerEntity) : AZStd::make_unique()) + , m_instanceEntityMapper(AZ::Interface::Get()) + , m_templateInstanceMapper(AZ::Interface::Get()) + { AZ_Assert(m_instanceEntityMapper, "Instance Entity Mapper Interface could not be found. " "It is a requirement for the Prefab Instance class. " "Check that it is being correctly initialized."); - m_templateInstanceMapper = AZ::Interface::Get(); - AZ_Assert(m_templateInstanceMapper, "Template Instance Mapper Interface could not be found. " "It is a requirement for the Prefab Instance class. " "Check that it is being correctly initialized."); - m_alias = GenerateInstanceAlias(); - m_containerEntity = containerEntity ? AZStd::move(containerEntity) - : AZStd::make_unique(); + if (parent) + { + AliasPath absoluteInstancePath = m_parent->GetAbsoluteInstanceAliasPath(); + absoluteInstancePath.Append(m_alias); + absoluteInstancePath.Append(PrefabDomUtils::ContainerEntityName); + + AZ::EntityId newContainerEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteInstancePath); + m_containerEntity->SetId(newContainerEntityId); + } + RegisterEntity(m_containerEntity->GetId(), PrefabDomUtils::ContainerEntityName); } @@ -69,12 +98,12 @@ namespace AzToolsFramework } } - const TemplateId& Instance::GetTemplateId() const + TemplateId Instance::GetTemplateId() const { return m_templateId; } - void Instance::SetTemplateId(const TemplateId& templateId) + void Instance::SetTemplateId(TemplateId templateId) { // If we aren't changing the template Id, there's no need to unregister / re-register if (templateId == m_templateId) @@ -295,20 +324,21 @@ namespace AzToolsFramework } Instance& Instance::AddInstance(AZStd::unique_ptr instance) - { - InstanceAlias newInstanceAlias = GenerateInstanceAlias(); - return AddInstance(AZStd::move(instance), newInstanceAlias); - } - - Instance& Instance::AddInstance(AZStd::unique_ptr instance, InstanceAlias newInstanceAlias) { AZ_Assert(instance.get(), "instance argument is nullptr"); + + if (instance->GetInstanceAlias().empty()) + { + instance->m_alias = GenerateInstanceAlias(); + } + AZ_Assert( - m_nestedInstances.find(newInstanceAlias) == m_nestedInstances.end(), + m_nestedInstances.find(instance->GetInstanceAlias()) == m_nestedInstances.end(), "InstanceAlias' unique id collision, this should never happen."); + instance->m_parent = this; - instance->m_alias = newInstanceAlias; - return *(m_nestedInstances[newInstanceAlias] = std::move(instance)); + auto& alias = instance->GetInstanceAlias(); + return *(m_nestedInstances[alias] = AZStd::move(instance)); } void Instance::DetachNestedInstances(const AZStd::function)>& callback) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index 39d364b4bb..50a39268fe 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -65,6 +65,9 @@ namespace AzToolsFramework Instance(); explicit Instance(AZStd::unique_ptr containerEntity); + explicit Instance(InstanceOptionalReference parent); + explicit Instance(AZStd::unique_ptr containerEntity, InstanceOptionalReference parent); + explicit Instance(InstanceAlias alias); virtual ~Instance(); Instance(const Instance& rhs) = delete; @@ -72,8 +75,8 @@ namespace AzToolsFramework static void Reflect(AZ::ReflectContext* context); - const TemplateId& GetTemplateId() const; - void SetTemplateId(const TemplateId& templateId); + TemplateId GetTemplateId() const; + void SetTemplateId(TemplateId templateId); const AZ::IO::Path& GetTemplateSourcePath() const; void SetTemplateSourcePath(AZ::IO::PathView sourcePath); @@ -97,7 +100,6 @@ namespace AzToolsFramework void Reset(); Instance& AddInstance(AZStd::unique_ptr instance); - Instance& AddInstance(AZStd::unique_ptr instance, InstanceAlias instanceAlias); AZStd::unique_ptr DetachNestedInstance(const InstanceAlias& instanceAlias); void DetachNestedInstances(const AZStd::function)>& callback); @@ -184,6 +186,8 @@ namespace AzToolsFramework private: static constexpr const char s_aliasPathSeparator = '/'; + Instance(AZStd::unique_ptr containerEntity, InstanceOptionalReference parent, InstanceAlias alias); + void ClearEntities(); void RemoveEntities(const AZStd::function&)>& filter); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp index 65c498499d..5c7e5070f0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp @@ -27,7 +27,7 @@ namespace AzToolsFramework } - bool TemplateInstanceMapper::RegisterTemplate(const TemplateId& templateId) + bool TemplateInstanceMapper::RegisterTemplate(TemplateId templateId) { const bool result = m_templateIdToInstancesMap.emplace(templateId, InstanceSet()).second; AZ_Assert(result, @@ -39,7 +39,7 @@ namespace AzToolsFramework return result; } - bool TemplateInstanceMapper::UnregisterTemplate(const TemplateId& templateId) + bool TemplateInstanceMapper::UnregisterTemplate(TemplateId templateId) { const bool result = m_templateIdToInstancesMap.erase(templateId) != 0; AZ_Assert(result, @@ -53,7 +53,7 @@ namespace AzToolsFramework bool TemplateInstanceMapper::RegisterInstanceToTemplate(Instance& instance) { - const TemplateId& templateId = instance.GetTemplateId(); + TemplateId templateId = instance.GetTemplateId(); if (templateId == InvalidTemplateId) { return false; @@ -79,7 +79,7 @@ namespace AzToolsFramework found->second.erase(&instance) != 0; } - InstanceSetConstReference TemplateInstanceMapper::FindInstancesOwnedByTemplate(const TemplateId& templateId) const + InstanceSetConstReference TemplateInstanceMapper::FindInstancesOwnedByTemplate(TemplateId templateId) const { auto found = m_templateIdToInstancesMap.find(templateId); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.h index 307996b381..a2330c30d2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.h @@ -26,10 +26,10 @@ namespace AzToolsFramework TemplateInstanceMapper(); ~TemplateInstanceMapper() override; - InstanceSetConstReference FindInstancesOwnedByTemplate(const TemplateId& templateId) const override; + InstanceSetConstReference FindInstancesOwnedByTemplate(TemplateId templateId) const override; - bool RegisterTemplate(const TemplateId& templateId); - bool UnregisterTemplate(const TemplateId& templateId); + bool RegisterTemplate(TemplateId templateId); + bool UnregisterTemplate(TemplateId templateId); protected: bool RegisterInstanceToTemplate(Instance& instance) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapperInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapperInterface.h index 6473d5e937..475b456425 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapperInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapperInterface.h @@ -24,7 +24,7 @@ namespace AzToolsFramework AZ_RTTI(TemplateInstanceMapperInterface, "{5DCCCDAA-3441-4266-9670-B349386E0129}"); virtual ~TemplateInstanceMapperInterface() = default; - virtual InstanceSetConstReference FindInstancesOwnedByTemplate(const TemplateId& templateId) const = 0; + virtual InstanceSetConstReference FindInstancesOwnedByTemplate(TemplateId templateId) const = 0; protected: // Only the Instance class is allowed to register and unregister Instances. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.cpp index 800a90c622..8efb62d7e8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.cpp @@ -122,12 +122,12 @@ namespace AzToolsFramework !m_instanceName.empty(); } - const TemplateId& Link::GetSourceTemplateId() const + TemplateId Link::GetSourceTemplateId() const { return m_sourceTemplateId; } - const TemplateId& Link::GetTargetTemplateId() const + TemplateId Link::GetTargetTemplateId() const { return m_targetTemplateId; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.h index 00530c4337..aa11262bdf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.h @@ -48,8 +48,8 @@ namespace AzToolsFramework bool IsValid() const; - const TemplateId& GetSourceTemplateId() const; - const TemplateId& GetTargetTemplateId() const; + TemplateId GetSourceTemplateId() const; + TemplateId GetTargetTemplateId() const; LinkId GetId() const; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 6ef2d756fb..29bad78b1c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -92,7 +92,17 @@ namespace AzToolsFramework AZStd::unique_ptr PrefabSystemComponent::CreatePrefab( const AZStd::vector& entities, AZStd::vector>&& instancesToConsume, - AZ::IO::PathView filePath, AZStd::unique_ptr containerEntity, bool shouldCreateLinks) + AZ::IO::PathView filePath, AZStd::unique_ptr containerEntity, InstanceOptionalReference parent, + bool shouldCreateLinks) + { + AZStd::unique_ptr newInstance = AZStd::make_unique(AZStd::move(containerEntity), parent); + CreatePrefab(entities, AZStd::move(instancesToConsume), filePath, newInstance, shouldCreateLinks); + return newInstance; + } + + void PrefabSystemComponent::CreatePrefab( + const AZStd::vector& entities, AZStd::vector>&& instancesToConsume, + AZ::IO::PathView filePath, AZStd::unique_ptr& newInstance, bool shouldCreateLinks) { AZ::IO::Path relativeFilePath = m_prefabLoader.GenerateRelativePath(filePath); if (GetTemplateIdFromFilePath(relativeFilePath) != InvalidTemplateId) @@ -101,11 +111,9 @@ namespace AzToolsFramework "Filepath %s has already been registered with the Prefab System Component", relativeFilePath.c_str()); - return nullptr; + return; } - AZStd::unique_ptr newInstance = AZStd::make_unique(AZStd::move(containerEntity)); - for (AZ::Entity* entity : entities) { AZ_Assert(entity, "Prefab - Null entity passed in during Create Prefab"); @@ -136,8 +144,6 @@ namespace AzToolsFramework { newInstance->SetTemplateId(newTemplateId); } - - return newInstance; } void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude) @@ -171,7 +177,7 @@ namespace AzToolsFramework } } - void PrefabSystemComponent::UpdatePrefabInstances(const TemplateId& templateId, InstanceOptionalReference instanceToExclude) + void PrefabSystemComponent::UpdatePrefabInstances(TemplateId templateId, InstanceOptionalReference instanceToExclude) { m_instanceUpdateExecutor.AddTemplateInstancesToQueue(templateId, instanceToExclude); } @@ -256,7 +262,8 @@ namespace AzToolsFramework } } - AZStd::unique_ptr PrefabSystemComponent::InstantiatePrefab(AZ::IO::PathView filePath) + AZStd::unique_ptr PrefabSystemComponent::InstantiatePrefab( + AZ::IO::PathView filePath, InstanceOptionalReference parent) { // Retrieve the template id for the source prefab filepath Prefab::TemplateId templateId = GetTemplateIdFromFilePath(filePath); @@ -276,10 +283,11 @@ namespace AzToolsFramework return nullptr; } - return InstantiatePrefab(templateId); + return InstantiatePrefab(templateId, parent); } - AZStd::unique_ptr PrefabSystemComponent::InstantiatePrefab(const TemplateId& templateId) + AZStd::unique_ptr PrefabSystemComponent::InstantiatePrefab( + TemplateId templateId, InstanceOptionalReference parent) { TemplateReference instantiatingTemplate = FindTemplate(templateId); @@ -292,7 +300,7 @@ namespace AzToolsFramework return nullptr; } - auto newInstance = AZStd::make_unique(); + auto newInstance = AZStd::make_unique(parent); Instance::EntityList newEntities; if (!PrefabDomUtils::LoadInstanceFromPrefabDom(*newInstance, newEntities, instantiatingTemplate->get().GetPrefabDom())) { @@ -354,7 +362,7 @@ namespace AzToolsFramework return newTemplateId; } - TemplateReference PrefabSystemComponent::FindTemplate(const TemplateId& id) + TemplateReference PrefabSystemComponent::FindTemplate(TemplateId id) { auto found = m_templateIdMap.find(id); if (found != m_templateIdMap.end()) @@ -466,7 +474,7 @@ namespace AzToolsFramework templateToChange.SetFilePath(filePath); } - void PrefabSystemComponent::RemoveTemplate(const TemplateId& templateId) + void PrefabSystemComponent::RemoveTemplate(TemplateId templateId) { auto findTemplateResult = FindTemplate(templateId); if (!findTemplateResult.has_value()) @@ -553,8 +561,8 @@ namespace AzToolsFramework } LinkId PrefabSystemComponent::AddLink( - const TemplateId& sourceTemplateId, - const TemplateId& targetTemplateId, + TemplateId sourceTemplateId, + TemplateId targetTemplateId, PrefabDomValue::MemberIterator& instanceIterator, InstanceOptionalReference instance) { @@ -616,8 +624,8 @@ namespace AzToolsFramework } LinkId PrefabSystemComponent::CreateLink( - const TemplateId& linkTargetId, - const TemplateId& linkSourceId, + TemplateId linkTargetId, + TemplateId linkSourceId, const InstanceAlias& instanceAlias, const PrefabDomConstReference linkPatches, const LinkId& linkId) @@ -774,7 +782,7 @@ namespace AzToolsFramework } } - bool PrefabSystemComponent::IsTemplateDirty(const TemplateId& templateId) + bool PrefabSystemComponent::IsTemplateDirty(TemplateId templateId) { auto templateRef = FindTemplate(templateId); @@ -786,7 +794,7 @@ namespace AzToolsFramework return false; } - void PrefabSystemComponent::SetTemplateDirtyFlag(const TemplateId& templateId, bool dirty) + void PrefabSystemComponent::SetTemplateDirtyFlag(TemplateId templateId, bool dirty) { auto templateRef = FindTemplate(templateId); @@ -940,7 +948,7 @@ namespace AzToolsFramework return true; } - bool PrefabSystemComponent::GenerateLinksForNewTemplate(const TemplateId& newTemplateId, Instance& instance) + bool PrefabSystemComponent::GenerateLinksForNewTemplate(TemplateId newTemplateId, Instance& instance) { TemplateReference newTemplateReference = FindTemplate(newTemplateId); if (!newTemplateReference.has_value()) @@ -980,7 +988,7 @@ namespace AzToolsFramework } const PrefabDomValue& source = instanceSourceReference->get(); - const TemplateId& nestedTemplateId = GetTemplateIdFromFilePath(source.GetString()); + TemplateId nestedTemplateId = GetTemplateIdFromFilePath(source.GetString()); if (nestedTemplateId == InvalidTemplateId) { AZ_Error("Prefab", false, diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h index 746c306c2b..19c7aeb8a9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h @@ -84,7 +84,7 @@ namespace AzToolsFramework * @param id A unique id of a Template. * @return Reference of Template if the Template exists. */ - TemplateReference FindTemplate(const TemplateId& id) override; + TemplateReference FindTemplate(TemplateId id) override; /** * Find Link with given Link id from Prefab System Component. @@ -112,7 +112,7 @@ namespace AzToolsFramework * Remove the Template associated with the given id from Prefab System Component. * @param templateId A unique id of a Template. */ - void RemoveTemplate(const TemplateId& templateId) override; + void RemoveTemplate(TemplateId templateId) override; /** * Remove all Templates from the Prefab System Component. @@ -121,17 +121,21 @@ namespace AzToolsFramework /** * Generates a new Prefab Instance based on the Template whose source is stored in filepath. - * @param filePath the path to the prefab source file containing the template being instantiated. + * @param filePath The path to the prefab source file containing the template being instantiated. + * @param parent Reference of the target instance the instantiated instance will be placed under. * @return A unique_ptr to the newly instantiated instance. Null if operation failed. */ - AZStd::unique_ptr InstantiatePrefab(AZ::IO::PathView filePath) override; + AZStd::unique_ptr InstantiatePrefab( + AZ::IO::PathView filePath, InstanceOptionalReference parent = AZStd::nullopt) override; /** - * Generates a new Prefab Instance based on the Template referenced by templateId - * @param templateId the id of the template being instantiated. + * Generates a new Prefab Instance based on the Template referenced by templateId. + * @param templateId The id of the template being instantiated. + * @param parent Reference of the target instance the instantiated instance will be placed under. * @return A unique_ptr to the newly instantiated instance. Null if operation failed. */ - AZStd::unique_ptr InstantiatePrefab(const TemplateId& templateId) override; + AZStd::unique_ptr InstantiatePrefab( + TemplateId templateId, InstanceOptionalReference parent = AZStd::nullopt) override; /** * Add a new Link into Prefab System Component and create a unique id for it. @@ -142,8 +146,8 @@ namespace AzToolsFramework * @return A unique id for the new Link. */ LinkId AddLink( - const TemplateId& sourceTemplateId, - const TemplateId& targetTemplateId, + TemplateId sourceTemplateId, + TemplateId targetTemplateId, PrefabDomValue::MemberIterator& instanceIterator, InstanceOptionalReference instance) override; @@ -157,8 +161,8 @@ namespace AzToolsFramework * @return A unique id for the new Link. */ LinkId CreateLink( - const TemplateId& linkTargetId, - const TemplateId& linkSourceId, + TemplateId linkTargetId, + TemplateId linkSourceId, const InstanceAlias& instanceAlias, const PrefabDomConstReference linkPatches, const LinkId& linkId = InvalidLinkId) override; @@ -181,14 +185,14 @@ namespace AzToolsFramework * @param templateId The id of the template to query. * @return The value of the dirty flag on the template. */ - bool IsTemplateDirty(const TemplateId& templateId) override; + bool IsTemplateDirty(TemplateId templateId) override; /** * Sets the dirty flag of the template to the value provided. * @param templateId The id of the template to flag. * @param dirty The new value of the dirty flag. */ - void SetTemplateDirtyFlag(const TemplateId& templateId, bool dirty) override; + void SetTemplateDirtyFlag(TemplateId templateId, bool dirty) override; bool AreDirtyTemplatesPresent(TemplateId rootTemplateId) override; @@ -200,20 +204,21 @@ namespace AzToolsFramework /** * Builds a new Prefab Template out of entities and instances and returns the first instance comprised of - * these entities and instances - * @param entities A vector of entities that will be used in the new instance. May be empty + * these entities and instances. + * @param entities A vector of entities that will be used in the new instance. May be empty. * @param instances A vector of Prefab Instances that will be nested in the new instance, will be consumed and moved. - * May be empty - * @param filePath the path to associate the template of the new instance to. + * May be empty. + * @param filePath The path to associate the template of the new instance to. * @param containerEntity The container entity for the prefab to be created. It will be created if a nullptr is provided. + * @param parent Reference of an instance the created instance will be placed under, if given. * @param shouldCreateLinks The flag indicating if links should be created between the templates of the instance * and its nested instances. - * @return A pointer to the newly created instance. nullptr on failure + * @return A pointer to the newly created instance. nullptr on failure. */ AZStd::unique_ptr CreatePrefab( const AZStd::vector& entities, AZStd::vector>&& instancesToConsume, AZ::IO::PathView filePath, AZStd::unique_ptr containerEntity = nullptr, - bool ShouldCreateLinks = true) override; + InstanceOptionalReference parent = AZStd::nullopt, bool shouldCreateLinks = true) override; PrefabDom& FindTemplateDom(TemplateId templateId) override; @@ -232,11 +237,26 @@ namespace AzToolsFramework * * @param templateId The id of the Template owning Instances to update. */ - void UpdatePrefabInstances(const TemplateId& templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt); + void UpdatePrefabInstances(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt); private: AZ_DISABLE_COPY_MOVE(PrefabSystemComponent); + /** + * Builds a new Prefab Template out of entities and instances and returns the first instance comprised of + * these entities and instances. + * @param entities A vector of entities that will be used in the new instance. May be empty. + * @param instances A vector of Prefab Instances that will be nested in the new instance, will be consumed and moved. + * May be empty. + * @param filePath The path to associate the template of the new instance to. + * @param instance Reference of a pointer to the newly created instance which needs initiation. + * @param shouldCreateLinks The flag indicating if links should be created between the templates of the instance + * and its nested instances. + */ + void CreatePrefab(const AZStd::vector& entities, + AZStd::vector>&& instancesToConsume, AZ::IO::PathView filePath, + AZStd::unique_ptr& instance, bool shouldCreateLinks); + /** * Updates all the linked Instances corresponding to the linkIds in the provided queue. * Queue gets populated with more linkId lists as linked instances are updated. Updating stops when the queue is empty. @@ -310,7 +330,7 @@ namespace AzToolsFramework * @param instance The instance that the template was created from. This needs to be editable for inserting linkId into it. * @return bool on whether the operation succeeded */ - bool GenerateLinksForNewTemplate(const TemplateId& newTemplateId, Instance& instance); + bool GenerateLinksForNewTemplate(TemplateId newTemplateId, Instance& instance); /** * Create a unique Template id for newly created Template. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h index 1f59088518..3baaf9ae12 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h @@ -29,28 +29,28 @@ namespace AzToolsFramework public: AZ_RTTI(PrefabSystemComponentInterface, "{8E95A029-67F9-4F74-895F-DDBFE29516A0}"); - virtual TemplateReference FindTemplate(const TemplateId& id) = 0; + virtual TemplateReference FindTemplate(TemplateId id) = 0; virtual LinkReference FindLink(const LinkId& id) = 0; virtual TemplateId AddTemplate(const AZ::IO::Path& filePath, PrefabDom prefabDom) = 0; virtual void UpdateTemplateFilePath(TemplateId templateId, const AZ::IO::PathView& filePath) = 0; - virtual void RemoveTemplate(const TemplateId& templateId) = 0; + virtual void RemoveTemplate(TemplateId templateId) = 0; virtual void RemoveAllTemplates() = 0; - virtual LinkId AddLink(const TemplateId& sourceTemplateId, const TemplateId& targetTemplateId, + virtual LinkId AddLink(TemplateId sourceTemplateId, TemplateId targetTemplateId, PrefabDomValue::MemberIterator& instanceIterator, InstanceOptionalReference instance) = 0; //creates a new Link virtual LinkId CreateLink( - const TemplateId& linkTargetId, const TemplateId& linkSourceId, const InstanceAlias& instanceAlias, + TemplateId linkTargetId, TemplateId linkSourceId, const InstanceAlias& instanceAlias, const PrefabDomConstReference linkPatches, const LinkId& linkId = InvalidLinkId) = 0; virtual void RemoveLink(const LinkId& linkId) = 0; virtual TemplateId GetTemplateIdFromFilePath(AZ::IO::PathView filePath) const = 0; - virtual bool IsTemplateDirty(const TemplateId& templateId) = 0; - virtual void SetTemplateDirtyFlag(const TemplateId& templateId, bool dirty) = 0; + virtual bool IsTemplateDirty(TemplateId templateId) = 0; + virtual void SetTemplateDirtyFlag(TemplateId templateId, bool dirty) = 0; //! Recursive function to check if the template is dirty or if any dirty templates are presents in the links of the template. //! @param rootTemplateId The id of the template provided as the beginning template to check the outgoing links. @@ -69,11 +69,14 @@ namespace AzToolsFramework virtual void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) = 0; virtual void PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; - virtual AZStd::unique_ptr InstantiatePrefab(AZ::IO::PathView filePath) = 0; - virtual AZStd::unique_ptr InstantiatePrefab(const TemplateId& templateId) = 0; + virtual AZStd::unique_ptr InstantiatePrefab( + AZ::IO::PathView filePath, InstanceOptionalReference parent = AZStd::nullopt) = 0; + virtual AZStd::unique_ptr InstantiatePrefab( + TemplateId templateId, InstanceOptionalReference parent = AZStd::nullopt) = 0; virtual AZStd::unique_ptr CreatePrefab(const AZStd::vector& entities, AZStd::vector>&& instancesToConsume, AZ::IO::PathView filePath, - AZStd::unique_ptr containerEntity = nullptr, bool ShouldCreateLinks = true) = 0; + AZStd::unique_ptr containerEntity = nullptr, InstanceOptionalReference parent = AZStd::nullopt, + bool shouldCreateLinks = true) = 0; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp index fe3555a853..385e9b149b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp @@ -33,7 +33,7 @@ namespace AzToolsFramework void PrefabUndoInstance::Capture( const PrefabDom& initialState, const PrefabDom& endState, - const TemplateId& templateId) + TemplateId templateId) { m_templateId = templateId; @@ -136,8 +136,8 @@ namespace AzToolsFramework } void PrefabUndoInstanceLink::Capture( - const TemplateId& targetId, - const TemplateId& sourceId, + TemplateId targetId, + TemplateId sourceId, const InstanceAlias& instanceAlias, PrefabDom linkPatches, const LinkId linkId) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h index 1b04852c37..0af94f86cc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h @@ -49,7 +49,7 @@ namespace AzToolsFramework void Capture( const PrefabDom& initialState, const PrefabDom& endState, - const TemplateId& templateId); + TemplateId templateId); void Undo() override; void Redo() override; @@ -95,8 +95,8 @@ namespace AzToolsFramework //capture for add/remove void Capture( - const TemplateId& targetId, - const TemplateId& sourceId, + TemplateId targetId, + TemplateId sourceId, const InstanceAlias& instanceAlias, PrefabDom linkPatches = PrefabDom(), const LinkId linkId = InvalidLinkId); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabCreateBenchmarks.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabCreateBenchmarks.cpp index 64c4058a47..8cc5e5f4d2 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabCreateBenchmarks.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabCreateBenchmarks.cpp @@ -72,7 +72,7 @@ namespace Benchmark AZStd::unique_ptr instance = m_prefabSystemComponent->CreatePrefab( entities , {} - , m_pathString); + , m_pathString); state.PauseTiming(); @@ -165,7 +165,7 @@ namespace Benchmark { nestedInstanceRoot = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(nestedInstanceRoot) ), + MakeInstanceList(AZStd::move(nestedInstanceRoot)), m_paths[instanceCounter]); } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp index 0d95049e76..92a30b89f2 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp @@ -36,7 +36,7 @@ namespace Benchmark AZStd::unique_ptr enclosingInstance = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(nestedInstance) ), + MakeInstanceList(AZStd::move(nestedInstance)), enclosingTemplatePath); TemplateId templateToInstantiateId = enclosingInstance->GetTemplateId(); @@ -99,7 +99,7 @@ namespace Benchmark { currentInstanceRoot = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(currentInstanceRoot) ), + MakeInstanceList(AZStd::move(currentInstanceRoot)), m_paths[currentDepth - 1]); } @@ -151,7 +151,7 @@ namespace Benchmark { currentInstanceRoot = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(currentInstanceRoot) ), + MakeInstanceList(AZStd::move(currentInstanceRoot)), m_paths[currentDepth]); } @@ -214,7 +214,7 @@ namespace Benchmark currentInstanceRoot = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(currentInstanceRoot), AZStd::move(extraNestedInstance) ), + MakeInstanceList(AZStd::move(currentInstanceRoot), AZStd::move(extraNestedInstance)), m_paths[currentDepth]); } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp index 14eee84b7d..72489b07a1 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp @@ -54,7 +54,7 @@ namespace UnitTest // Create a street prefab that nests the car and sportscar instances created above. The container entity will be created as part of the process. AZStd::unique_ptr streetInstance = - m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(carInstance), AZStd::move(sportsCarInstance) ), "test/street"); + m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList(AZStd::move(carInstance), AZStd::move(sportsCarInstance)), "test/street"); ASSERT_TRUE(streetInstance); m_instanceMap[StreetEntityName] = streetInstance.get(); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp index ebe35a5402..a08b0bf6c2 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp @@ -320,7 +320,7 @@ namespace UnitTest Instance& addedInstance = *addedInstancePtr; //create a first instance where the instance will be removed - AZStd::unique_ptr firstInstance = m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(addedInstancePtr) ), "test/path"); + AZStd::unique_ptr firstInstance = m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList(AZStd::move(addedInstancePtr)), "test/path"); ASSERT_TRUE(firstInstance); //get added instance alias diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstantiateTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstantiateTests.cpp index 09aac8dcf5..cc8217a915 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstantiateTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstantiateTests.cpp @@ -44,11 +44,11 @@ namespace UnitTest ASSERT_TRUE(firstInstance); AZStd::unique_ptr secondInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(firstInstance) ), "test/path2"); + MakeInstanceList(AZStd::move(firstInstance)), "test/path2"); ASSERT_TRUE(secondInstance); AZStd::unique_ptr thirdInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(secondInstance) ), "test/path3"); + MakeInstanceList(AZStd::move(secondInstance)), "test/path3"); ASSERT_TRUE(thirdInstance); //Instantiate it diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.cpp index b805e224bf..55e3c158a1 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.cpp @@ -21,8 +21,8 @@ namespace UnitTest using namespace AzToolsFramework::Prefab; LinkData CreateLinkData( const InstanceData& instanceData, - const TemplateId& sourceTemplateId, - const TemplateId& targetTemplateId) + TemplateId sourceTemplateId, + TemplateId targetTemplateId) { LinkData newLinkData; newLinkData.m_instanceData = instanceData; diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.h b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.h index e3048469c5..0082ad5951 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.h +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.h @@ -17,8 +17,8 @@ namespace UnitTest { LinkData CreateLinkData( const InstanceData& instanceData, - const AzToolsFramework::Prefab::TemplateId& sourceTemplateId, - const AzToolsFramework::Prefab::TemplateId& targetTemplateId); + AzToolsFramework::Prefab::TemplateId sourceTemplateId, + AzToolsFramework::Prefab::TemplateId targetTemplateId); InstanceData CreateInstanceDataWithNoPatches( const AZStd::string& name, diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.cpp index 334f01fc3a..c71013320f 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.cpp @@ -56,7 +56,7 @@ namespace UnitTest } void ValidateInstances( - const TemplateId& templateId, + TemplateId templateId, const PrefabDomValue& expectedContent, const PrefabDomPath& contentPath, bool isContentAnInstance, @@ -204,7 +204,7 @@ namespace UnitTest } void ValidateEntitiesOfInstances( - const AzToolsFramework::Prefab::TemplateId& templateId, + AzToolsFramework::Prefab::TemplateId templateId, const AzToolsFramework::Prefab::PrefabDom& expectedPrefabDom, const AZStd::vector& entityAliases) { @@ -219,7 +219,7 @@ namespace UnitTest } void ValidateNestedInstancesOfInstances( - const AzToolsFramework::Prefab::TemplateId& templateId, + AzToolsFramework::Prefab::TemplateId templateId, const AzToolsFramework::Prefab::PrefabDom& expectedPrefabDom, const AZStd::vector& nestedInstanceAliases) { diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.h b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.h index f90a91ea3c..b1ba7fbca0 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.h +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.h @@ -118,7 +118,7 @@ namespace UnitTest const PrefabDomValue& patches); void ValidateInstances( - const TemplateId& templateId, + TemplateId templateId, const PrefabDomValue& expectedContent, const PrefabDomPath& contentPath, bool isContentAnInstance = false, @@ -147,12 +147,12 @@ namespace UnitTest void ComparePrefabDomValues(PrefabDomValueConstReference valueA, PrefabDomValueConstReference valueB); void ValidateEntitiesOfInstances( - const AzToolsFramework::Prefab::TemplateId& templateId, + AzToolsFramework::Prefab::TemplateId templateId, const AzToolsFramework::Prefab::PrefabDom& expectedPrefabDom, const AZStd::vector& entityAliases); void ValidateNestedInstancesOfInstances( - const AzToolsFramework::Prefab::TemplateId& templateId, + AzToolsFramework::Prefab::TemplateId templateId, const AzToolsFramework::Prefab::PrefabDom& expectedPrefabDom, const AZStd::vector& nestedInstanceAliases); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestUndoFixture.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestUndoFixture.cpp index cb44f9c401..2420b14d6c 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestUndoFixture.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestUndoFixture.cpp @@ -18,14 +18,14 @@ namespace UnitTest { //create two prefabs for test //create prefab 1 - firstInstance = AZStd::move(m_prefabSystemComponent->CreatePrefab({ }, {}, "test/path0")); + firstInstance = AZStd::move(m_prefabSystemComponent->CreatePrefab({}, {}, "test/path0")); ASSERT_TRUE(firstInstance); //get template id ownerId = firstInstance->GetTemplateId(); //create prefab 2 - secondInstance = AZStd::move(m_prefabSystemComponent->CreatePrefab({ }, {}, "test/path1")); + secondInstance = AZStd::move(m_prefabSystemComponent->CreatePrefab({}, {}, "test/path1")); ASSERT_TRUE(secondInstance); //get template id diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp index baded6d43e..7427c06f43 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp @@ -120,7 +120,7 @@ namespace UnitTest // Create an enclosing Template with 0 entities and 1 nested Instance. AZStd::unique_ptr nestedInstance1 = m_prefabSystemComponent->InstantiatePrefab(newNestedTemplateId); - AZStd::unique_ptr newEnclosingInstance = m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(nestedInstance1) ), PrefabMockFilePath); + AZStd::unique_ptr newEnclosingInstance = m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList(AZStd::move(nestedInstance1)), PrefabMockFilePath); TemplateId newEnclosingTemplateId = newEnclosingInstance->GetTemplateId(); EXPECT_TRUE(newEnclosingTemplateId != InvalidTemplateId); PrefabDom& newEnclosingTemplateDom = m_prefabSystemComponent->FindTemplateDom(newEnclosingTemplateId); @@ -284,7 +284,7 @@ namespace UnitTest AZStd::unique_ptr nestedInstance2 = m_prefabSystemComponent->InstantiatePrefab(newNestedTemplateId); AZStd::unique_ptr newEnclosingInstance = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(nestedInstance1), AZStd::move(nestedInstance2) ), + MakeInstanceList(AZStd::move(nestedInstance1), AZStd::move(nestedInstance2)), PrefabMockFilePath); TemplateId newEnclosingTemplateId = newEnclosingInstance->GetTemplateId(); EXPECT_TRUE(newEnclosingTemplateId != InvalidTemplateId); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp index 6f90e245f7..242c226c7e 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp @@ -41,7 +41,7 @@ namespace UnitTest AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr wheel2UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle), AZStd::move(wheel2UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle), AZStd::move(wheel2UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); const AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); @@ -51,7 +51,7 @@ namespace UnitTest AZStd::unique_ptr axle2UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr spareWheelUnderCar = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axle1UnderCar), AZStd::move(axle2UnderCar), AZStd::move(spareWheelUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axle1UnderCar), AZStd::move(axle2UnderCar), AZStd::move(spareWheelUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); const AZStd::vector wheelInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -93,7 +93,7 @@ namespace UnitTest // Create an axle with 0 entities and 1 wheel instance. AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -105,7 +105,7 @@ namespace UnitTest AZStd::unique_ptr axle1UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr axle2UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axle1UnderCar), AZStd::move(axle2UnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axle1UnderCar), AZStd::move(axle2UnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); @@ -151,7 +151,7 @@ namespace UnitTest // Create an axle with 0 entities and 1 wheel instance. AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); const AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -159,7 +159,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axleUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); @@ -205,7 +205,7 @@ namespace UnitTest // Create an axle with 0 entities and 1 wheel instance. AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); const AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -213,7 +213,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axleUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); @@ -253,7 +253,7 @@ namespace UnitTest AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr wheel2UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle), AZStd::move(wheel2UnderAxle) ), + MakeInstanceList(AZStd::move(wheel1UnderAxle), AZStd::move(wheel2UnderAxle) ), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); @@ -265,7 +265,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axle1UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axle1UnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axle1UnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); @@ -320,7 +320,7 @@ namespace UnitTest // Create an axle with 0 entities and 1 wheel instance. AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); const AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -328,7 +328,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axleUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); @@ -381,7 +381,7 @@ namespace UnitTest // Create an axle with 0 entities and 1 wheel instance. AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); const AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -389,7 +389,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axleUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateWithPatchesTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateWithPatchesTests.cpp index c17763f778..1fa638bc29 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateWithPatchesTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateWithPatchesTests.cpp @@ -68,7 +68,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axleUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp index df4f394cc5..c815af3b7a 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.cpp +++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp @@ -558,7 +558,7 @@ namespace AZ AZStd::string instanceAlias = GetInstanceAlias(instance); // Create a new unmodified prefab Instance for the nested slice instance. - auto nestedInstance = AZStd::make_unique(); + auto nestedInstance = AZStd::make_unique(AZStd::move(instanceAlias)); AzToolsFramework::Prefab::Instance::EntityList newEntities; if (!AzToolsFramework::Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom( *nestedInstance, newEntities, nestedTemplate->get().GetPrefabDom())) @@ -742,7 +742,7 @@ namespace AZ instanceToTemplateInterface->GenerateDomForInstance(topLevelInstanceDomBefore, *topLevelInstance); // Use the deterministic instance alias for this new instance - AzToolsFramework::Prefab::Instance& addedInstance = topLevelInstance->AddInstance(AZStd::move(nestedInstance), instanceAlias); + AzToolsFramework::Prefab::Instance& addedInstance = topLevelInstance->AddInstance(AZStd::move(nestedInstance)); AzToolsFramework::Prefab::PrefabDom topLevelInstanceDomAfter; instanceToTemplateInterface->GenerateDomForInstance(topLevelInstanceDomAfter, *topLevelInstance); From 18b947fd0016146f1399d7e5bba3992a023cf979 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 1 Oct 2021 12:11:55 -0500 Subject: [PATCH 112/115] Changed the AssetManager DispatchEvents function to continously pump the (#4432) AssetBus of queued functions until empty. This replicates the old behavior of the EBusQueuePolicy::Execute function that would continue to execute functions if new ones were added during the execution of the current queue. Split the TestFixture class from the AssetHandler and EBus handler for the DynamicSliceInstanceSpawnerTests and PrefabInstanceSpawnerTest. This avoids the AssetMananager destructor from deleting the test fixture if the call to UnregisterHandler is ever removed. This also allows the memory allocators to get online earlier. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/AzCore/Asset/AssetManager.cpp | 7 +- .../DynamicSliceInstanceSpawnerTests.cpp | 143 ++++++++++-------- .../Code/Tests/PrefabInstanceSpawnerTests.cpp | 143 ++++++++++-------- Gems/Vegetation/Code/Tests/VegetationTest.h | 25 ++- 4 files changed, 180 insertions(+), 138 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp index 8eb620f69e..06bb0b0cac 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp @@ -551,8 +551,6 @@ namespace AZ { PrepareShutDown(); - DispatchEvents(); - // Acquire the asset lock to make sure nobody else is trying to do anything fancy with assets AZStd::scoped_lock assetLock(m_assetMutex); @@ -575,7 +573,10 @@ namespace AZ { AZ_PROFILE_FUNCTION(AzCore); AssetManagerNotificationBus::Broadcast(&AssetManagerNotificationBus::Events::OnAssetEventsDispatchBegin); - AssetBus::ExecuteQueuedEvents(); + while (AssetBus::QueuedEventCount()) + { + AssetBus::ExecuteQueuedEvents(); + } AssetManagerNotificationBus::Broadcast(&AssetManagerNotificationBus::Events::OnAssetEventsDispatchEnd); } diff --git a/Gems/Vegetation/Code/Tests/DynamicSliceInstanceSpawnerTests.cpp b/Gems/Vegetation/Code/Tests/DynamicSliceInstanceSpawnerTests.cpp index 9838a7b6a1..26d8028522 100644 --- a/Gems/Vegetation/Code/Tests/DynamicSliceInstanceSpawnerTests.cpp +++ b/Gems/Vegetation/Code/Tests/DynamicSliceInstanceSpawnerTests.cpp @@ -50,80 +50,25 @@ namespace UnitTest } }; - // To test Dynamic Slice spawning, we need to mock up enough of the asset management system and the dynamic slice - // asset handling to pretend like we're loading/unloading dynamic slices successfully. - class DynamicSliceInstanceSpawnerTests - : public VegetationComponentTests - , public UnitTest::SetRestoreFileIOBaseRAII - , public Vegetation::DescriptorNotificationBus::Handler + class DynamicSliceAssetCatalogAndHandler + : public Vegetation::DescriptorNotificationBus::Handler , public AZ::Data::AssetCatalogRequestBus::Handler , public AZ::Data::AssetHandler , public AZ::Data::AssetCatalog , public AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler { public: - DynamicSliceInstanceSpawnerTests() - : UnitTest::SetRestoreFileIOBaseRAII(m_fileIOMock) + DynamicSliceAssetCatalogAndHandler() { - AZ::IO::MockFileIOBase::InstallDefaultReturns(m_fileIOMock); - } - - void RegisterComponentDescriptors() override - { - m_app.RegisterComponentDescriptor(MockDynamicSliceInstanceVegetationSystemComponent::CreateDescriptor()); - } - - void SetUp() override - { - VegetationComponentTests::SetUp(); - - // Create a real Asset Mananger, and point to ourselves as the handler for DynamicSliceAsset. - AZ::AllocatorInstance::Create(); - AZ::AllocatorInstance::Create(); - - - // Initialize the job manager with 1 thread for the AssetManager to use. - AZ::JobManagerDesc jobDesc; - AZ::JobManagerThreadDesc threadDesc; - jobDesc.m_workerThreads.push_back(threadDesc); - m_jobManager = aznew AZ::JobManager(jobDesc); - m_jobContext = aznew AZ::JobContext(*m_jobManager); - AZ::JobContext::SetGlobalContext(m_jobContext); - - AZ::Data::AssetManager::Descriptor descriptor; - AZ::Data::AssetManager::Create(descriptor); - AZ::Data::AssetManager::Instance().RegisterHandler(this, AZ::AzTypeInfo::Uuid()); - AZ::Data::AssetManager::Instance().RegisterCatalog(this, AZ::AzTypeInfo::Uuid()); - - m_app.RegisterComponentDescriptor(AZ::SliceComponent::CreateDescriptor()); - // Intercept messages for finding assets by name and creating/destroying slices. AZ::Data::AssetCatalogRequestBus::Handler::BusConnect(); AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler::BusConnect(); } - void TearDown() override + ~DynamicSliceAssetCatalogAndHandler() { - // Give the AssetManager a chance to fire off any lingering events and perform cleanup for any - // dynamic slice assets we loaded. - AZ::Data::AssetManager::Instance().DispatchEvents(); - AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler::BusDisconnect(); - AZ::Data::AssetManager::Instance().UnregisterCatalog(this); - AZ::Data::AssetManager::Instance().UnregisterHandler(this); - AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect(); - - AZ::Data::AssetManager::Destroy(); - - AZ::JobContext::SetGlobalContext(nullptr); - delete m_jobContext; - delete m_jobManager; - - AZ::AllocatorInstance::Destroy(); - AZ::AllocatorInstance::Destroy(); - - VegetationComponentTests::TearDown(); } // Helper methods: @@ -207,7 +152,7 @@ namespace UnitTest AZStd::string GetAssetPathById(const AZ::Data::AssetId& /*id*/) override { return m_assetPath; } AZ::Data::AssetId GetAssetIdByPath(const char* /*path*/, const AZ::Data::AssetType& /*typeToRegister*/, bool /*autoRegisterIfNotFound*/) override { return m_assetId; } AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& /*id*/) override - { + { AZ::Data::AssetInfo assetInfo; assetInfo.m_assetId = m_assetId; assetInfo.m_assetType = AZ::AzTypeInfo::Uuid(); @@ -244,9 +189,77 @@ namespace UnitTest AZStd::string m_assetPath; AZ::Data::AssetId m_assetId; int m_numOnLoadedCalls = 0; + }; + // To test Dynamic Slice spawning, we need to mock up enough of the asset management system and the dynamic slice + // asset handling to pretend like we're loading/unloading dynamic slices successfully. + class DynamicSliceInstanceSpawnerTests + : public VegetationComponentTests + { + public: + DynamicSliceInstanceSpawnerTests() + : m_restoreFileIO(m_fileIOMock) + { + AZ::IO::MockFileIOBase::InstallDefaultReturns(m_fileIOMock); + } + void SetUp() override + { + VegetationComponentTests::SetUp(); + + // Create a real Asset Mananger, and point to ourselves as the handler for DynamicSliceAsset. + AZ::AllocatorInstance::Create(); + AZ::AllocatorInstance::Create(); + + // Initialize the job manager with 1 thread for the AssetManager to use. + AZ::JobManagerDesc jobDesc; + AZ::JobManagerThreadDesc threadDesc; + jobDesc.m_workerThreads.push_back(threadDesc); + m_jobManager = aznew AZ::JobManager(jobDesc); + m_jobContext = aznew AZ::JobContext(*m_jobManager); + AZ::JobContext::SetGlobalContext(m_jobContext); + + AZ::Data::AssetManager::Descriptor descriptor; + AZ::Data::AssetManager::Create(descriptor); + m_testHandler = AZStd::make_unique(); + AZ::Data::AssetManager::Instance().RegisterHandler(m_testHandler.get(), AZ::AzTypeInfo::Uuid()); + AZ::Data::AssetManager::Instance().RegisterCatalog(m_testHandler.get(), AZ::AzTypeInfo::Uuid()); + + m_app.RegisterComponentDescriptor(AZ::SliceComponent::CreateDescriptor()); + } + + void TearDown() override + { + // Clear out the list of queued AssetBus Events before unregistering the AssetHandler + // to make sure pending references to Asset instances are cleared + AZ::Data::AssetManager::Instance().DispatchEvents(); + AZ::Data::AssetManager::Instance().UnregisterHandler(m_testHandler.get()); + AZ::Data::AssetManager::Instance().UnregisterCatalog(m_testHandler.get()); + AZ::Data::AssetManager::Destroy(); + + m_testHandler.reset(); + + AZ::JobContext::SetGlobalContext(nullptr); + delete m_jobContext; + delete m_jobManager; + + AZ::AllocatorInstance::Destroy(); + AZ::AllocatorInstance::Destroy(); + + VegetationComponentTests::TearDown(); + } + + void RegisterComponentDescriptors() override + { + m_app.RegisterComponentDescriptor(MockDynamicSliceInstanceVegetationSystemComponent::CreateDescriptor()); + } + + protected: + AZStd::unique_ptr m_testHandler; + + private: AZ::JobManager* m_jobManager{ nullptr }; AZ::JobContext* m_jobContext{ nullptr }; + SetRestoreFileIOBaseRAII m_restoreFileIO; ::testing::NiceMock m_fileIOMock; }; @@ -276,7 +289,7 @@ namespace UnitTest Vegetation::DynamicSliceInstanceSpawner instanceSpawner2; // Give the second instance spawner a non-default asset reference. - CreateAndSetMockAsset(instanceSpawner2, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner2, AZ::Uuid::CreateRandom(), "test"); // The test is written this way because only the == operator is overloaded. EXPECT_TRUE(!(instanceSpawner1 == instanceSpawner2)); @@ -292,14 +305,14 @@ namespace UnitTest EXPECT_TRUE(instanceSpawner.HasEmptyAssetReferences()); // This will test the asset load. - CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); // Test the asset unload works too. - Vegetation::DescriptorNotificationBus::Handler::BusConnect(&instanceSpawner); + m_testHandler->Vegetation::DescriptorNotificationBus::Handler::BusConnect(&instanceSpawner); instanceSpawner.UnloadAssets(); EXPECT_FALSE(instanceSpawner.IsLoaded()); EXPECT_FALSE(instanceSpawner.IsSpawnable()); - Vegetation::DescriptorNotificationBus::Handler::BusDisconnect(); + m_testHandler->Vegetation::DescriptorNotificationBus::Handler::BusDisconnect(); } TEST_F(DynamicSliceInstanceSpawnerTests, CreateAndDestroyInstance) @@ -308,7 +321,7 @@ namespace UnitTest Vegetation::DynamicSliceInstanceSpawner instanceSpawner; - CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); instanceSpawner.OnRegisterUniqueDescriptor(); diff --git a/Gems/Vegetation/Code/Tests/PrefabInstanceSpawnerTests.cpp b/Gems/Vegetation/Code/Tests/PrefabInstanceSpawnerTests.cpp index b0d88f2d63..3398dba20f 100644 --- a/Gems/Vegetation/Code/Tests/PrefabInstanceSpawnerTests.cpp +++ b/Gems/Vegetation/Code/Tests/PrefabInstanceSpawnerTests.cpp @@ -51,76 +51,21 @@ namespace UnitTest } }; - // To test prefab spawning, we need to mock up enough of the asset management system and the spawnable - // asset handling to pretend like we're loading/unloading spawnables successfully. - class PrefabInstanceSpawnerTests - : public VegetationComponentTests - , public UnitTest::SetRestoreFileIOBaseRAII - , public Vegetation::DescriptorNotificationBus::Handler + class PrefabInstanceHandlerAndCatalog + : public Vegetation::DescriptorNotificationBus::Handler , public AZ::Data::AssetCatalogRequestBus::Handler , public AZ::Data::AssetHandler , public AZ::Data::AssetCatalog { public: - PrefabInstanceSpawnerTests() - : UnitTest::SetRestoreFileIOBaseRAII(m_fileIOMock) + PrefabInstanceHandlerAndCatalog() { - AZ::IO::MockFileIOBase::InstallDefaultReturns(m_fileIOMock); - AzFramework::MockSpawnableEntitiesInterface::InstallDefaultReturns(m_spawnableEntitiesInterfaceMock); - } - - void RegisterComponentDescriptors() override - { - m_app.RegisterComponentDescriptor(MockPrefabInstanceVegetationSystemComponent::CreateDescriptor()); - } - - void SetUp() override - { - VegetationComponentTests::SetUp(); - - // Create a real Asset Mananger, and point to ourselves as the handler for Spawnable. - AZ::AllocatorInstance::Create(); - AZ::AllocatorInstance::Create(); - - - // Initialize the job manager with 1 thread for the AssetManager to use. - AZ::JobManagerDesc jobDesc; - AZ::JobManagerThreadDesc threadDesc; - jobDesc.m_workerThreads.push_back(threadDesc); - m_jobManager = aznew AZ::JobManager(jobDesc); - m_jobContext = aznew AZ::JobContext(*m_jobManager); - AZ::JobContext::SetGlobalContext(m_jobContext); - - AZ::Data::AssetManager::Descriptor descriptor; - AZ::Data::AssetManager::Create(descriptor); - AZ::Data::AssetManager::Instance().RegisterHandler(this, AZ::AzTypeInfo::Uuid()); - AZ::Data::AssetManager::Instance().RegisterCatalog(this, AZ::AzTypeInfo::Uuid()); - - // Intercept messages for finding assets by name. AZ::Data::AssetCatalogRequestBus::Handler::BusConnect(); } - void TearDown() override + ~PrefabInstanceHandlerAndCatalog() { - // Give the AssetManager a chance to fire off any lingering events and perform cleanup for any - // spawnable assets we loaded. - AZ::Data::AssetManager::Instance().DispatchEvents(); - - AZ::Data::AssetManager::Instance().UnregisterCatalog(this); - AZ::Data::AssetManager::Instance().UnregisterHandler(this); - AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect(); - - AZ::Data::AssetManager::Destroy(); - - AZ::JobContext::SetGlobalContext(nullptr); - delete m_jobContext; - delete m_jobManager; - - AZ::AllocatorInstance::Destroy(); - AZ::AllocatorInstance::Destroy(); - - VegetationComponentTests::TearDown(); } // Helper methods: @@ -227,9 +172,79 @@ namespace UnitTest AZStd::string m_assetPath; AZ::Data::AssetId m_assetId; int m_numOnLoadedCalls = 0; + }; + // To test Dynamic Slice spawning, we need to mock up enough of the asset management system and the dynamic slice + // asset handling to pretend like we're loading/unloading dynamic slices successfully. + class PrefabInstanceSpawnerTests + : public VegetationComponentTests + { + public: + PrefabInstanceSpawnerTests() + : m_restoreFileIO(m_fileIOMock) + { + AZ::IO::MockFileIOBase::InstallDefaultReturns(m_fileIOMock); + AzFramework::MockSpawnableEntitiesInterface::InstallDefaultReturns(m_spawnableEntitiesInterfaceMock); + } + + void SetUp() override + { + VegetationComponentTests::SetUp(); + + // Create a real Asset Mananger, and point to ourselves as the handler for DynamicSliceAsset. + AZ::AllocatorInstance::Create(); + AZ::AllocatorInstance::Create(); + + // Initialize the job manager with 1 thread for the AssetManager to use. + AZ::JobManagerDesc jobDesc; + AZ::JobManagerThreadDesc threadDesc; + jobDesc.m_workerThreads.push_back(threadDesc); + m_jobManager = aznew AZ::JobManager(jobDesc); + m_jobContext = aznew AZ::JobContext(*m_jobManager); + AZ::JobContext::SetGlobalContext(m_jobContext); + + AZ::Data::AssetManager::Descriptor descriptor; + AZ::Data::AssetManager::Create(descriptor); + m_testHandler = AZStd::make_unique(); + AZ::Data::AssetManager::Instance().RegisterHandler(m_testHandler.get(), AZ::AzTypeInfo::Uuid()); + AZ::Data::AssetManager::Instance().RegisterCatalog(m_testHandler.get(), AZ::AzTypeInfo::Uuid()); + + m_app.RegisterComponentDescriptor(AZ::SliceComponent::CreateDescriptor()); + } + + void TearDown() override + { + // Clear out the list of queued AssetBus Events before unregistering the AssetHandler + // to make sure pending references to Asset instances are cleared + AZ::Data::AssetManager::Instance().DispatchEvents(); + AZ::Data::AssetManager::Instance().UnregisterHandler(m_testHandler.get()); + AZ::Data::AssetManager::Instance().UnregisterCatalog(m_testHandler.get()); + AZ::Data::AssetManager::Destroy(); + + m_testHandler.reset(); + + AZ::JobContext::SetGlobalContext(nullptr); + delete m_jobContext; + delete m_jobManager; + + AZ::AllocatorInstance::Destroy(); + AZ::AllocatorInstance::Destroy(); + + VegetationComponentTests::TearDown(); + } + + void RegisterComponentDescriptors() override + { + m_app.RegisterComponentDescriptor(MockPrefabInstanceVegetationSystemComponent::CreateDescriptor()); + } + + protected: + AZStd::unique_ptr m_testHandler; + + private: AZ::JobManager* m_jobManager{ nullptr }; AZ::JobContext* m_jobContext{ nullptr }; + SetRestoreFileIOBaseRAII m_restoreFileIO; ::testing::NiceMock m_fileIOMock; ::testing::NiceMock m_spawnableEntitiesInterfaceMock; }; @@ -259,7 +274,7 @@ namespace UnitTest Vegetation::PrefabInstanceSpawner instanceSpawner2; // Give the second instance spawner a non-default asset reference. - CreateAndSetMockAsset(instanceSpawner2, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner2, AZ::Uuid::CreateRandom(), "test"); // The test is written this way because only the == operator is overloaded. EXPECT_TRUE(!(instanceSpawner1 == instanceSpawner2)); @@ -275,14 +290,14 @@ namespace UnitTest EXPECT_TRUE(instanceSpawner.HasEmptyAssetReferences()); // This will test the asset load. - CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); // Test the asset unload works too. - Vegetation::DescriptorNotificationBus::Handler::BusConnect(&instanceSpawner); + m_testHandler->Vegetation::DescriptorNotificationBus::Handler::BusConnect(&instanceSpawner); instanceSpawner.UnloadAssets(); EXPECT_FALSE(instanceSpawner.IsLoaded()); EXPECT_FALSE(instanceSpawner.IsSpawnable()); - Vegetation::DescriptorNotificationBus::Handler::BusDisconnect(); + m_testHandler->Vegetation::DescriptorNotificationBus::Handler::BusDisconnect(); } TEST_F(PrefabInstanceSpawnerTests, CreateAndDestroyInstance) @@ -291,7 +306,7 @@ namespace UnitTest Vegetation::PrefabInstanceSpawner instanceSpawner; - CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); instanceSpawner.OnRegisterUniqueDescriptor(); diff --git a/Gems/Vegetation/Code/Tests/VegetationTest.h b/Gems/Vegetation/Code/Tests/VegetationTest.h index cf7c9b70a1..2ae8ac9cca 100644 --- a/Gems/Vegetation/Code/Tests/VegetationTest.h +++ b/Gems/Vegetation/Code/Tests/VegetationTest.h @@ -21,21 +21,34 @@ namespace UnitTest { class VegetationComponentTests - : public ::testing::Test + : public ScopedAllocatorSetupFixture { protected: + VegetationComponentTests() + : ScopedAllocatorSetupFixture( + []() { + AZ::SystemAllocator::Descriptor desc; + desc.m_heap.m_fixedMemoryBlocksByteSize[0] = 20 * 1024 * 1024; + desc.m_stackRecordLevels = 20; + return desc; + }() + ) + { + } + AZ::ComponentApplication m_app; virtual void RegisterComponentDescriptors() {} void SetUp() override { - AZ::ComponentApplication::Descriptor appDesc; - appDesc.m_memoryBlocksByteSize = 20 * 1024 * 1024; - appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_NO_RECORDS; - appDesc.m_stackRecordLevels = 20; + if (AZ::Debug::AllocationRecords* records = AZ::AllocatorInstance::GetAllocator().GetRecords(); + records != nullptr) + { + records->SetMode(AZ::Debug::AllocationRecords::RECORD_NO_RECORDS); + } - m_app.Create(appDesc); + m_app.Create({}); RegisterComponentDescriptors(); } From 799ab8585bdf7ffa95b32d207bc68953272bec54 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Fri, 1 Oct 2021 12:24:57 -0700 Subject: [PATCH 113/115] Update MaterialEditor launcher to use platform traits for executable extensions (#4429) Signed-off-by: Steve Pham --- .../Code/Source/Material/EditorMaterialSystemComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index 83ddbf46c5..a6b595940f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -137,7 +137,7 @@ namespace AZ arguments.append(QString("--project-path=%1").arg(projectPath.c_str())); } - AtomToolsFramework::LaunchTool("MaterialEditor", ".exe", arguments); + AtomToolsFramework::LaunchTool("MaterialEditor", AZ_TRAIT_OS_EXECUTABLE_EXTENSION, arguments); } void EditorMaterialSystemComponent::OpenMaterialInspector( From 7018f16088c36377b88f86f79c6de3d03cb81beb Mon Sep 17 00:00:00 2001 From: Mikhail Naumov <82239319+AMZN-mnaumov@users.noreply.github.com> Date: Fri, 1 Oct 2021 15:16:45 -0500 Subject: [PATCH 114/115] Fixing undo/redo not updating transform pivot point (#4375) * Fixing undo/redo not updating transform pivot point Signed-off-by: Mikhail Naumov * PR feedback Signed-off-by: Mikhail Naumov * PR feedback Signed-off-by: Mikhail Naumov * fixing non-redo operations to still use batching (fixes some tests) Signed-off-by: Mikhail Naumov --- .../Prefab/Instance/InstanceToTemplateInterface.h | 3 ++- .../Instance/InstanceToTemplatePropagator.cpp | 4 ++-- .../Instance/InstanceToTemplatePropagator.h | 2 +- .../Prefab/Instance/InstanceUpdateExecutor.cpp | 7 ++++++- .../Prefab/Instance/InstanceUpdateExecutor.h | 2 +- .../Instance/InstanceUpdateExecutorInterface.h | 2 +- .../Prefab/PrefabPublicHandler.cpp | 2 +- .../Prefab/PrefabSystemComponent.cpp | 8 ++++---- .../Prefab/PrefabSystemComponent.h | 7 +++++-- .../Prefab/PrefabSystemComponentInterface.h | 2 +- .../AzToolsFramework/Prefab/PrefabUndo.cpp | 15 ++++++++++----- .../AzToolsFramework/Prefab/PrefabUndo.h | 1 + .../AzToolsFramework/Prefab/PrefabUndoHelpers.cpp | 2 +- 13 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h index b944ef159a..a8c717d6b0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h @@ -46,10 +46,11 @@ namespace AzToolsFramework //! Updates the template links (updating instances) for the given template and triggers propagation on its instances. //! @param providedPatch The patch to apply to the template. //! @param templateId The id of the template to update. + //! @param immediate An optional flag whether to apply the patch immediately (needed for Undo/Redos) or wait until next system tick. //! @param instanceToExclude An optional reference to an instance of the template being updated that should not be refreshes as part of propagation. //! Defaults to nullopt, which means that all instances will be refreshed. //! @return True if the template was patched correctly, false if the operation failed. - virtual bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; + virtual bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; virtual void ApplyPatchesToInstance(const AZ::EntityId& entityId, PrefabDom& patches, const Instance& instanceToAddPatches) = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp index 6b281bcbae..73acb9b8a4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp @@ -156,7 +156,7 @@ namespace AzToolsFramework } } - bool InstanceToTemplatePropagator::PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, InstanceOptionalReference instanceToExclude) + bool InstanceToTemplatePropagator::PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, bool immediate, InstanceOptionalReference instanceToExclude) { PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId); @@ -178,7 +178,7 @@ namespace AzToolsFramework (result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip), "Some of the patches were not successfully applied."); m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true); - m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, instanceToExclude); + m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, immediate, instanceToExclude); return true; } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.h index 75acb410c9..80fe7de8d5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.h @@ -33,7 +33,7 @@ namespace AzToolsFramework InstanceOptionalReference GetTopMostInstanceInHierarchy(AZ::EntityId entityId) override; - bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; + bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; void ApplyPatchesToInstance(const AZ::EntityId& entityId, PrefabDom& patches, const Instance& instanceToAddPatches) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp index 9ef74167a6..feea3ce25b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp @@ -52,7 +52,7 @@ namespace AzToolsFramework AZ::Interface::Unregister(this); } - void InstanceUpdateExecutor::AddTemplateInstancesToQueue(TemplateId instanceTemplateId, InstanceOptionalReference instanceToExclude) + void InstanceUpdateExecutor::AddTemplateInstancesToQueue(TemplateId instanceTemplateId, bool immediate, InstanceOptionalReference instanceToExclude) { auto findInstancesResult = m_templateInstanceMapperInterface->FindInstancesOwnedByTemplate(instanceTemplateId); @@ -79,6 +79,11 @@ namespace AzToolsFramework m_instancesUpdateQueue.emplace_back(instance); } } + + if (immediate) + { + UpdateTemplateInstancesInQueue(); + } } void InstanceUpdateExecutor::RemoveTemplateInstanceFromQueue(const Instance* instance) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h index ee461eae88..de2b483c4d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h @@ -31,7 +31,7 @@ namespace AzToolsFramework explicit InstanceUpdateExecutor(int instanceCountToUpdateInBatch = 0); - void AddTemplateInstancesToQueue(TemplateId instanceTemplateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; + void AddTemplateInstancesToQueue(TemplateId instanceTemplateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; bool UpdateTemplateInstancesInQueue() override; virtual void RemoveTemplateInstanceFromQueue(const Instance* instance) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h index 8ad032e1d0..3b894efd21 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h @@ -23,7 +23,7 @@ namespace AzToolsFramework virtual ~InstanceUpdateExecutorInterface() = default; // Add all Instances of Template with given Id into a queue for updating them later. - virtual void AddTemplateInstancesToQueue(TemplateId instanceTemplateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; + virtual void AddTemplateInstancesToQueue(TemplateId instanceTemplateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; // Update Instances in the waiting queue. virtual bool UpdateTemplateInstancesInQueue() = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 41538d54e8..038f36eac9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1041,7 +1041,7 @@ namespace AzToolsFramework PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication"); command->SetParent(undoBatch.GetUndoBatch()); command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId()); - command->Redo(); + command->RedoBatched(); DuplicateNestedInstancesInInstance(commonOwningInstance->get(), instances, instanceDomAfter, duplicatedEntityAndInstanceIds, newInstanceAliasToOldInstanceMap); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 29bad78b1c..0ecde973c2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -146,9 +146,9 @@ namespace AzToolsFramework } } - void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude) + void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId, bool immediate, InstanceOptionalReference instanceToExclude) { - UpdatePrefabInstances(templateId, instanceToExclude); + UpdatePrefabInstances(templateId, immediate, instanceToExclude); auto templateIdToLinkIdsIterator = m_templateToLinkIdsMap.find(templateId); if (templateIdToLinkIdsIterator != m_templateToLinkIdsMap.end()) @@ -177,9 +177,9 @@ namespace AzToolsFramework } } - void PrefabSystemComponent::UpdatePrefabInstances(TemplateId templateId, InstanceOptionalReference instanceToExclude) + void PrefabSystemComponent::UpdatePrefabInstances(TemplateId templateId, bool immediate, InstanceOptionalReference instanceToExclude) { - m_instanceUpdateExecutor.AddTemplateInstancesToQueue(templateId, instanceToExclude); + m_instanceUpdateExecutor.AddTemplateInstancesToQueue(templateId, immediate, instanceToExclude); } void PrefabSystemComponent::UpdateLinkedInstances(AZStd::queue& linkIdsQueue) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h index 19c7aeb8a9..f640eb2f1b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h @@ -230,14 +230,17 @@ namespace AzToolsFramework */ void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) override; - void PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; + void PropagateTemplateChanges(TemplateId templateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; /** * Updates all Instances owned by a Template. * * @param templateId The id of the Template owning Instances to update. + * @param immediate An optional flag whether to apply the patch immediately (needed for Undo/Redos) or wait until next system tick. + * @param instanceToExclude An optional reference to an instance of the template being updated that should not be refreshes as part of propagation. + * Defaults to nullopt, which means that all instances will be refreshed. */ - void UpdatePrefabInstances(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt); + void UpdatePrefabInstances(TemplateId templateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt); private: AZ_DISABLE_COPY_MOVE(PrefabSystemComponent); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h index 3baaf9ae12..54ca951841 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h @@ -67,7 +67,7 @@ namespace AzToolsFramework virtual PrefabDom& FindTemplateDom(TemplateId templateId) = 0; virtual void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) = 0; - virtual void PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; + virtual void PropagateTemplateChanges(TemplateId templateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; virtual AZStd::unique_ptr InstantiatePrefab( AZ::IO::PathView filePath, InstanceOptionalReference parent = AZStd::nullopt) = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp index 385e9b149b..b298304e3b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp @@ -43,10 +43,15 @@ namespace AzToolsFramework void PrefabUndoInstance::Undo() { - m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId); + m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId, true); } void PrefabUndoInstance::Redo() + { + m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, true); + } + + void PrefabUndoInstance::RedoBatched() { m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId); } @@ -91,7 +96,7 @@ namespace AzToolsFramework void PrefabUndoEntityUpdate::Undo() { [[maybe_unused]] bool isPatchApplicationSuccessful = - m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId); + m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId, true); AZ_Error( "Prefab", isPatchApplicationSuccessful, @@ -102,7 +107,7 @@ namespace AzToolsFramework void PrefabUndoEntityUpdate::Redo() { [[maybe_unused]] bool isPatchApplicationSuccessful = - m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId); + m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, true); AZ_Error( "Prefab", isPatchApplicationSuccessful, @@ -113,7 +118,7 @@ namespace AzToolsFramework void PrefabUndoEntityUpdate::Redo(InstanceOptionalReference instanceToExclude) { [[maybe_unused]] bool isPatchApplicationSuccessful = - m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, instanceToExclude); + m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, false, instanceToExclude); AZ_Error( "Prefab", isPatchApplicationSuccessful, @@ -329,7 +334,7 @@ namespace AzToolsFramework //propagate the link changes link->get().UpdateTarget(); - m_prefabSystemComponentInterface->PropagateTemplateChanges(link->get().GetTargetTemplateId(), instanceToExclude); + m_prefabSystemComponentInterface->PropagateTemplateChanges(link->get().GetTargetTemplateId(), false, instanceToExclude); //mark as dirty m_prefabSystemComponentInterface->SetTemplateDirtyFlag(link->get().GetTargetTemplateId(), true); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h index 0af94f86cc..8669024df7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h @@ -53,6 +53,7 @@ namespace AzToolsFramework void Undo() override; void Redo() override; + void RedoBatched(); }; //! handles entity updates, such as when the values on an entity change diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp index 9c44fc7ffd..9803b55324 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp @@ -26,7 +26,7 @@ namespace AzToolsFramework PrefabUndoInstance* state = aznew Prefab::PrefabUndoInstance(undoMessage); state->Capture(instanceDomBeforeUpdate, instanceDomAfterUpdate, instance.GetTemplateId()); state->SetParent(undoBatch); - state->Redo(); + state->RedoBatched(); } LinkId CreateLink( From f3e6adce7fcff851e3d2a53d5590e4104f4daa16 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 1 Oct 2021 13:52:52 -0700 Subject: [PATCH 115/115] LYN-6882 release builds are executing code in asserts (#4305) * adding Windows/release to PR-validation builds Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * changing trace back to expand to nothing for release Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * typo Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * more fixes Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * fixing some more unused variable cases Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * renaming file in ScriptCanvas that causes a msbuild warning Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * reverting a previous change Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Debug/Trace.h | 20 +++++++++---------- .../AssetBrowser/Views/EntryDelegate.cpp | 2 +- .../Prefab/PrefabSystemComponent.cpp | 5 +++++ .../UI/Prefab/PrefabIntegrationManager.cpp | 2 +- Code/LauncherUnified/Launcher.cpp | 2 ++ .../native/utilities/assetUtils.cpp | 3 +++ .../Factory/TestImpactTestRunSuiteFactory.cpp | 8 ++++++-- .../Code/Tests/ImageProcessing_Test.cpp | 3 ++- .../Code/Source/Editor/ShaderAssetBuilder.cpp | 6 +++--- .../RHI/Code/Source/RHI/FrameScheduler.cpp | 2 +- .../Model/ModelAssetBuilderComponent.cpp | 2 ++ .../RPI.Reflect/Material/MaterialFunctor.cpp | 4 +++- Gems/Atom/Utils/Code/Source/PngFile.cpp | 4 ++-- .../BenchmarkAssetBuilderWorker.cpp | 2 ++ .../ScriptEventsNodePaletteTreeItemTypes.cpp | 2 ++ .../ScriptEvents/ScriptEventDefinition.h | 2 +- ...riptEventMethod.h => ScriptEventsMethod.h} | 0 ...EventMethod.cpp => ScriptEventsMethod.cpp} | 2 +- .../Code/Tests/ScriptEventsTestFixture.h | 2 +- .../Code/scriptevents_common_files.cmake | 4 ++-- .../Rendering/Atom/TangentSpaceHelper.cpp | 2 ++ cmake/Projects.cmake | 6 +++++- .../build/Platform/Windows/build_config.json | 1 + 23 files changed, 58 insertions(+), 28 deletions(-) rename Gems/ScriptEvents/Code/Include/ScriptEvents/{ScriptEventMethod.h => ScriptEventsMethod.h} (100%) rename Gems/ScriptEvents/Code/Source/{ScriptEventMethod.cpp => ScriptEventsMethod.cpp} (99%) diff --git a/Code/Framework/AzCore/AzCore/Debug/Trace.h b/Code/Framework/AzCore/AzCore/Debug/Trace.h index a1334d334e..507ba48e53 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Trace.h +++ b/Code/Framework/AzCore/AzCore/Debug/Trace.h @@ -262,17 +262,17 @@ namespace AZ #else // !AZ_ENABLE_TRACING - #define AZ_Assert(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_Error(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_ErrorOnce(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_Warning(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_WarningOnce(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_TracePrintf(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_TracePrintfOnce(...) AZ_UNUSED(__VA_ARGS__); + #define AZ_Assert(...) + #define AZ_Error(...) + #define AZ_ErrorOnce(...) + #define AZ_Warning(...) + #define AZ_WarningOnce(...) + #define AZ_TracePrintf(...) + #define AZ_TracePrintfOnce(...) - #define AZ_Verify(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_VerifyError(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_VerifyWarning(...) AZ_UNUSED(__VA_ARGS__); + #define AZ_Verify(expression, ...) AZ_UNUSED(expression) + #define AZ_VerifyError(window, expression, ...) AZ_UNUSED(expression) + #define AZ_VerifyWarning(window, expression, ...) AZ_UNUSED(expression) #endif // AZ_ENABLE_TRACING diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp index 755c59b55b..b463381638 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp @@ -290,7 +290,7 @@ namespace AzToolsFramework absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathOneChild; break; } - bool pixmapLoadedSuccess = pixmap.load(absoluteIconPath.c_str()); + [[maybe_unused]] bool pixmapLoadedSuccess = pixmap.load(absoluteIconPath.c_str()); AZ_Assert(pixmapLoadedSuccess, "Error loading Branch Icons in SearchEntryDelegate"); m_branchIcons[static_cast(branchType)] = pixmap; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 0ecde973c2..4f8f575a7b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -579,10 +579,13 @@ namespace AzToolsFramework Template& targetTemplate = targetTemplateReference->get(); +#if defined(AZ_ENABLE_TRACING) Template& sourceTemplate = sourceTemplateReference->get(); AZStd::string_view instanceName(instanceIterator->name.GetString(), instanceIterator->name.GetStringLength()); + const AZStd::string& targetTemplateFilePath = targetTemplate.GetFilePath().Native(); const AZStd::string& sourceTemplateFilePath = sourceTemplate.GetFilePath().Native(); +#endif LinkId newLinkId = CreateUniqueLinkId(); Link newLink(newLinkId); @@ -911,8 +914,10 @@ namespace AzToolsFramework return false; } +#if defined(AZ_ENABLE_TRACING) Template& sourceTemplate = sourceTemplateReference->get(); Template& targetTemplate = targetTemplateReference->get(); +#endif AZStd::string_view instanceName(instanceIterator->name.GetString(), instanceIterator->name.GetStringLength()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 9b7f2fff10..34152f8287 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -1160,7 +1160,7 @@ namespace AzToolsFramework AZStd::string unsavedPrefabFileName = unsavedPrefabFileLabel->property("FilePath").toString().toUtf8().data(); AzToolsFramework::Prefab::TemplateId unsavedPrefabTemplateId = s_prefabSystemComponentInterface->GetTemplateIdFromFilePath(unsavedPrefabFileName.data()); - bool isTemplateSavedSuccessfully = s_prefabLoaderInterface->SaveTemplate(unsavedPrefabTemplateId); + [[maybe_unused]] bool isTemplateSavedSuccessfully = s_prefabLoaderInterface->SaveTemplate(unsavedPrefabTemplateId); AZ_Error("Prefab", isTemplateSavedSuccessfully, "Prefab '%s' could not be saved successfully.", unsavedPrefabFileName.c_str()); } } diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp index 27aab074ef..0ef9cdfc3b 100644 --- a/Code/LauncherUnified/Launcher.cpp +++ b/Code/LauncherUnified/Launcher.cpp @@ -627,8 +627,10 @@ namespace O3DELauncher AZ_TracePrintf("Launcher", "Application is configured for VFS"); AZ_TracePrintf("Launcher", "Log and cache files will be written to the Cache directory on your host PC"); +#if defined(AZ_ENABLE_TRACING) constexpr const char* message = "If your game does not run, check any of the following:\n" "\t- Verify the remote_ip address is correct in bootstrap.cfg"; +#endif if (mainInfo.m_additionalVfsResolution) { AZ_TracePrintf("Launcher", "%s\n%s", message, mainInfo.m_additionalVfsResolution) diff --git a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp index c0e907f2d5..cacd6c4cc9 100644 --- a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp @@ -164,7 +164,10 @@ namespace AssetUtilsInternal AZ::SettingsRegistryMergeUtils::DumperSettings apDumperSettings; apDumperSettings.m_prettifyOutput = true; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning apDumperSettings.m_includeFilter = [&AssetProcessorUserSettingsRootKey](AZStd::string_view path) + AZ_POP_DISABLE_WARNING { // The AssetUtils only updates the following keys in the registry // Dump them all out to the setreg file diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/Source/Artifact/Factory/TestImpactTestRunSuiteFactory.cpp b/Code/Tools/TestImpactFramework/Runtime/Code/Source/Artifact/Factory/TestImpactTestRunSuiteFactory.cpp index b7a44d43ea..f39cfaaf10 100644 --- a/Code/Tools/TestImpactFramework/Runtime/Code/Source/Artifact/Factory/TestImpactTestRunSuiteFactory.cpp +++ b/Code/Tools/TestImpactFramework/Runtime/Code/Source/Artifact/Factory/TestImpactTestRunSuiteFactory.cpp @@ -64,9 +64,11 @@ namespace TestImpact return !name.starts_with("DISABLED_") && name.find("/DISABLED_") == AZStd::string::npos; }; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr + // in the capture. Newer versions issue unused warning const auto getDuration = [Keys](const AZ::rapidxml::xml_node<>* node) + AZ_POP_DISABLE_WARNING { - AZ_UNUSED(Keys); const AZStd::string duration = node->first_attribute(Keys[DurationKey])->value(); return AZStd::chrono::milliseconds(static_cast(AZStd::stof(duration) * 1000.f)); }; @@ -79,9 +81,11 @@ namespace TestImpact for (auto testcase_node = testsuite_node->first_node(Keys[TestCaseKey]); testcase_node; testcase_node = testcase_node->next_sibling()) { + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the capture. + // Newer versions issue unused warning const auto getStatus = [Keys](const AZ::rapidxml::xml_node<>* node) + AZ_POP_DISABLE_WARNING { - AZ_UNUSED(Keys); const AZStd::string status = node->first_attribute(Keys[StatusKey])->value(); if (status == Keys[RunKey]) { diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index c4240306c4..c72e1dc309 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -860,8 +860,9 @@ namespace UnitTest { continue; } - +#if defined(AZ_ENABLE_TRACING) auto formatInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(pixelFormat); +#endif ColorSpace sourceColorSpace = srcImage->HasImageFlags(EIF_SRGBRead) ? ColorSpace::sRGB : ColorSpace::linear; ICompressorPtr compressor = ICompressor::FindCompressor(pixelFormat, sourceColorSpace, true); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp index 2babba1ecc..3bc63b89a0 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp @@ -228,9 +228,9 @@ namespace AZ response.m_createJobOutputs.push_back(jobDescriptor); } // for all request.m_enabledPlatforms - const AZStd::sys_time_t createJobsEndStamp = AZStd::GetTimeNowMicroSecond(); - const u64 createJobDurationMicros = createJobsEndStamp - shaderAssetBuildTimestamp; - AZ_TracePrintf(ShaderAssetBuilderName, "CreateJobs for %s took %llu microseconds", fullPath.c_str(), createJobDurationMicros ); + AZ_TracePrintf( + ShaderAssetBuilderName, "CreateJobs for %s took %llu microseconds", fullPath.c_str(), + AZStd::GetTimeNowMicroSecond() - shaderAssetBuildTimestamp); response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; } diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp index 3363675d0e..0d3ac8216b 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp @@ -370,7 +370,7 @@ namespace AZ //It is possible for certain back ends to run out of SRG memory (due to fragmentation) in which case //we try to compact and re-compile SRGs. - RHI::ResultCode resultCode = m_device->CompactSRGMemory(); + [[maybe_unused]] RHI::ResultCode resultCode = m_device->CompactSRGMemory(); AZ_Assert(resultCode == RHI::ResultCode::Success, "SRG compaction failed and this can lead to a gpu crash."); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp index 1da16b44b6..9fc99e3ea4 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp @@ -1078,7 +1078,9 @@ namespace AZ template void ModelAssetBuilderComponent::ValidateStreamSize([[maybe_unused]] size_t expectedVertexCount, [[maybe_unused]] const AZStd::vector& bufferData, [[maybe_unused]] AZ::RHI::Format format, [[maybe_unused]] const char* streamName) const { +#if defined(AZ_ENABLE_TRACING) size_t actualVertexCount = (bufferData.size() * sizeof(T)) / RHI::GetFormatSize(format); +#endif AZ_Error(s_builderName, expectedVertexCount == actualVertexCount, "VertexStream '%s' does not match the expected vertex count. This typically means multiple sub-meshes have mis-matched vertex stream layouts (such as one having more uv sets than the other) but are assigned the same material in the dcc tool so they were merged.", streamName); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp index 0f70d0af35..52b6349ca0 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp @@ -417,14 +417,16 @@ namespace AZ template const Color& MaterialFunctor::EditorContext::GetMaterialPropertyValue (const MaterialPropertyIndex& index) const; template const Data::Instance& MaterialFunctor::EditorContext::GetMaterialPropertyValue> (const MaterialPropertyIndex& index) const; - void CheckPropertyAccess(const MaterialPropertyIndex& index, const MaterialPropertyFlags& materialPropertyDependencies, [[maybe_unused]] const MaterialPropertiesLayout& materialPropertiesLayout) + void CheckPropertyAccess([[maybe_unused]] const MaterialPropertyIndex& index, [[maybe_unused]] const MaterialPropertyFlags& materialPropertyDependencies, [[maybe_unused]] const MaterialPropertiesLayout& materialPropertiesLayout) { +#if defined(AZ_ENABLE_TRACING) if (!materialPropertyDependencies.test(index.GetIndex())) { const MaterialPropertyDescriptor* propertyDescriptor = materialPropertiesLayout.GetPropertyDescriptor(index); AZ_Error("MaterialFunctor", false, "Material functor accessing an unregistered material property '%s'.", propertyDescriptor ? propertyDescriptor->GetName().GetCStr() : ""); } +#endif } const MaterialPropertyValue& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue(const MaterialPropertyIndex& index) const diff --git a/Gems/Atom/Utils/Code/Source/PngFile.cpp b/Gems/Atom/Utils/Code/Source/PngFile.cpp index 09a5d950e5..28f5374d88 100644 --- a/Gems/Atom/Utils/Code/Source/PngFile.cpp +++ b/Gems/Atom/Utils/Code/Source/PngFile.cpp @@ -21,7 +21,7 @@ namespace AZ (*errorHandler)(error_msg); } - void PngImage_user_warning_fn(png_structp /*png_ptr*/, png_const_charp warning_msg) + void PngImage_user_warning_fn(png_structp /*png_ptr*/, [[maybe_unused]] png_const_charp warning_msg) { AZ_Warning("PngFile", false, "%s", warning_msg); } @@ -301,7 +301,7 @@ AZ_POP_DISABLE_WARNING return true; } - void PngFile::DefaultErrorHandler(const char* message) + void PngFile::DefaultErrorHandler([[maybe_unused]] const char* message) { AZ_Error("PngFile", false, "%s", message); } diff --git a/Gems/LmbrCentral/Code/Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderWorker.cpp index 22be22265a..da7181ae04 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderWorker.cpp @@ -253,10 +253,12 @@ namespace BenchmarkAssetBuilder // and 2 bytes of storage for text-based formats. // This is just an approximate total size because there's a bit of additional overhead // for asset headers and the other fields in the generated asset. +#if defined(AZ_ENABLE_TRACING) uint64_t approximateTotalStorageBytes = (settingsPtr->m_assetStorageType == AZ::DataStream::StreamType::ST_BINARY) ? UINT64_C(1) * totalGeneratedBytes : UINT64_C(2) * totalGeneratedBytes; +#endif AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Benchmark asset generation will generate %" PRIu64 " assets " diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp index 704f67e034..da0e9c6045 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp @@ -154,7 +154,9 @@ namespace ScriptCanvasEditor const ScriptEvents::ScriptEvent& definition = data->m_definition; +#if defined(AZ_ENABLE_TRACING) bool recategorize = previousDefinition ? definition.GetCategory().compare(previousDefinition->GetCategory()) != 0 : false; +#endif AZ_Warning("ScriptCanvas", !recategorize, "Unable to recategorize ScriptEvents events while open. Please close and re-open the Script Canvas Editor to see the new categorization"); if (definition.GetName().empty()) diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventDefinition.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventDefinition.h index bc8112802b..a56e9b422b 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventDefinition.h +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventDefinition.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include namespace ScriptEvents diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventMethod.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsMethod.h similarity index 100% rename from Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventMethod.h rename to Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsMethod.h diff --git a/Gems/ScriptEvents/Code/Source/ScriptEventMethod.cpp b/Gems/ScriptEvents/Code/Source/ScriptEventsMethod.cpp similarity index 99% rename from Gems/ScriptEvents/Code/Source/ScriptEventMethod.cpp rename to Gems/ScriptEvents/Code/Source/ScriptEventsMethod.cpp index 5b7bb590af..579c51a782 100644 --- a/Gems/ScriptEvents/Code/Source/ScriptEventMethod.cpp +++ b/Gems/ScriptEvents/Code/Source/ScriptEventsMethod.cpp @@ -6,7 +6,7 @@ * */ -#include "ScriptEvents/ScriptEventMethod.h" +#include "ScriptEvents/ScriptEventsMethod.h" #include #include diff --git a/Gems/ScriptEvents/Code/Tests/ScriptEventsTestFixture.h b/Gems/ScriptEvents/Code/Tests/ScriptEventsTestFixture.h index 78c7308dde..53d4fd58b9 100644 --- a/Gems/ScriptEvents/Code/Tests/ScriptEventsTestFixture.h +++ b/Gems/ScriptEvents/Code/Tests/ScriptEventsTestFixture.h @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include "ScriptEventTestUtilities.h" diff --git a/Gems/ScriptEvents/Code/scriptevents_common_files.cmake b/Gems/ScriptEvents/Code/scriptevents_common_files.cmake index 5938050f5d..a7ecd9e049 100644 --- a/Gems/ScriptEvents/Code/scriptevents_common_files.cmake +++ b/Gems/ScriptEvents/Code/scriptevents_common_files.cmake @@ -10,7 +10,7 @@ set(FILES Source/ScriptEventsSystemComponent.h Source/ScriptEventsSystemComponent.cpp Source/ScriptEventParameter.cpp - Source/ScriptEventMethod.cpp + Source/ScriptEventsMethod.cpp Source/ScriptEventsAssetRef.cpp Include/ScriptEvents/ScriptEventsGem.h Include/ScriptEvents/ScriptEventsAsset.h @@ -23,7 +23,7 @@ set(FILES Include/ScriptEvents/ScriptEventDefinition.h Include/ScriptEvents/ScriptEventDefinition.cpp Include/ScriptEvents/ScriptEvent.h - Include/ScriptEvents/ScriptEventMethod.h + Include/ScriptEvents/ScriptEventsMethod.h Include/ScriptEvents/ScriptEvent.cpp Include/ScriptEvents/ScriptEventParameter.h Include/ScriptEvents/ScriptEventSystem.h diff --git a/Gems/WhiteBox/Code/Source/Rendering/Atom/TangentSpaceHelper.cpp b/Gems/WhiteBox/Code/Source/Rendering/Atom/TangentSpaceHelper.cpp index a43b48d3b9..913778cc44 100644 --- a/Gems/WhiteBox/Code/Source/Rendering/Atom/TangentSpaceHelper.cpp +++ b/Gems/WhiteBox/Code/Source/Rendering/Atom/TangentSpaceHelper.cpp @@ -73,7 +73,9 @@ namespace WhiteBox for (AZ::u32 i = 0; i < triangleCount; ++i) { +#if defined(AZ_ENABLE_TRACING) const auto& trianglePositions = trianglesPositions[i]; +#endif const auto& triangleUVs = trianglesUVs[i]; const auto& triangleEdges = trianglesEdges[i]; diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index b21704ee85..6109229e72 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -10,7 +10,11 @@ include_guard() -set(LY_PROJECTS "" CACHE STRING "List of projects to enable, this can be a relative path to the engine root or an absolute path") +# Passing ${LY_PROJECTS} as the default since in project-centric LY_PROJECTS is defined by the project and +# we want to pick up that one as the value of the variable. +# Ideally this cache variable would be defined before the project sets LY_PROJECTS, but that would mean +# it would have to be defined in each project. +set(LY_PROJECTS "${LY_PROJECTS}" CACHE STRING "List of projects to enable, this can be a relative path to the engine root or an absolute path") #! ly_add_target_dependencies: adds module load dependencies for this target. # diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index e33025a4d9..c607c3d821 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -306,6 +306,7 @@ }, "release_vs2019": { "TAGS": [ + "default", "nightly-incremental", "nightly-clean", "weekly-build-metrics"