From ab45ea7efa3cacea1e0e809a3bc8e638bf183900 Mon Sep 17 00:00:00 2001 From: mnaumov Date: Fri, 28 May 2021 17:15:20 -0700 Subject: [PATCH 01/45] [ATOM-15631] First pass on exposing Display Mapper properties to Behavior Context --- .../Common/Code/3rdParty/ACES/ACES/Aces.h | 1 + .../DisplayMapperConfigurationDescriptor.h | 8 ++- .../DisplayMapperConfigurationDescriptor.cpp | 26 +++++++++ .../DisplayMapper/DisplayMapperComponentBus.h | 55 +++++++++++++++++++ .../DisplayMapper/DisplayMapperComponent.cpp | 1 - .../DisplayMapperComponentController.cpp | 33 +++++++++++ .../DisplayMapperComponentController.h | 10 ++++ .../EditorDisplayMapperComponent.cpp | 13 ++++- ...egration_commonfeatures_public_files.cmake | 1 + 9 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h diff --git a/Gems/Atom/Feature/Common/Code/3rdParty/ACES/ACES/Aces.h b/Gems/Atom/Feature/Common/Code/3rdParty/ACES/ACES/Aces.h index 472ef160be..cd9dca68e3 100644 --- a/Gems/Atom/Feature/Common/Code/3rdParty/ACES/ACES/Aces.h +++ b/Gems/Atom/Feature/Common/Code/3rdParty/ACES/ACES/Aces.h @@ -177,4 +177,5 @@ namespace AZ } // namespace Render AZ_TYPE_INFO_SPECIALIZE(Render::DisplayMapperOperationType, "{41CA80B1-9E0D-41FB-A235-9638D2A905A5}"); + AZ_TYPE_INFO_SPECIALIZE(Render::OutputDeviceTransformType, "{B94085B7-C0D4-466A-A791-188A4559EC8D}"); } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h index 4dc090b831..22c866447e 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h @@ -12,11 +12,13 @@ #pragma once +#include + #include + #include #include #include -#include namespace AZ { @@ -33,6 +35,7 @@ namespace AZ AZ_TYPE_INFO(AcesParameterOverrides, "{3EE8C0D4-3792-46C0-B91C-B89A81C36B91}"); static void Reflect(ReflectContext* context); + // Load preconfigured preset for specific ODT mode defined by m_preset void LoadPreset(); // When enabled allows parameter overrides for ACES configuration @@ -98,6 +101,5 @@ namespace AZ DisplayMapperConfigurationDescriptor m_config; }; - - } // namespace RPI + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp index e91e125b40..0858381fc5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp @@ -23,6 +23,15 @@ namespace AZ { if (auto serializeContext = azrtti_cast(context)) { + serializeContext->Enum() + ->Version(0) + ->Value("48Nits", OutputDeviceTransformType::OutputDeviceTransformType_48Nits) + ->Value("1000Nits", OutputDeviceTransformType::OutputDeviceTransformType_1000Nits) + ->Value("2000Nits", OutputDeviceTransformType::OutputDeviceTransformType_2000Nits) + ->Value("4000Nits", OutputDeviceTransformType::OutputDeviceTransformType_4000Nits) + ->Value("NumOutputDeviceTransformTypes", OutputDeviceTransformType::NumOutputDeviceTransformTypes) + ; + serializeContext->Class() ->Version(0) ->Field("OverrideDefaults", &AcesParameterOverrides::m_overrideDefaults) @@ -38,6 +47,22 @@ namespace AZ ->Field("SurroundGamma", &AcesParameterOverrides::m_surroundGamma) ->Field("Gamma", &AcesParameterOverrides::m_gamma); } + + if (auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("AcesParameterOverrides") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "render") + ->Attribute(AZ::Script::Attributes::Module, "render") + ->Constructor() + ->Method("LoadPreset", &AcesParameterOverrides::LoadPreset) + ->Property("overrideDefaults", BehaviorValueProperty(&AcesParameterOverrides::m_overrideDefaults)) + ->Property("preset", BehaviorValueProperty(&AcesParameterOverrides::m_preset)) + ->Property("alterSurround", BehaviorValueProperty(&AcesParameterOverrides::m_alterSurround)) + ->Property("applyDesaturation", BehaviorValueProperty(&AcesParameterOverrides::m_applyDesaturation)) + ->Property("applyCATD60toD65", BehaviorValueProperty(&AcesParameterOverrides::m_applyCATD60toD65)) + ; + } } void AcesParameterOverrides::LoadPreset() @@ -76,6 +101,7 @@ namespace AZ ->Field("OperationType", &DisplayMapperConfigurationDescriptor::m_operationType) ->Field("LdrGradingLutEnabled", &DisplayMapperConfigurationDescriptor::m_ldrGradingLutEnabled) ->Field("LdrColorGradingLut", &DisplayMapperConfigurationDescriptor::m_ldrColorGradingLut) + ->Field("AcesParameterOverrides", &DisplayMapperConfigurationDescriptor::m_acesParameterOverrides) ; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h new file mode 100644 index 0000000000..af57b69d3b --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h @@ -0,0 +1,55 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include +#include +#include + +namespace AZ +{ + namespace Render + { + struct AcesParameterOverrides; + + //! DisplayMapperComponentRequests provides an interface to request operations on a DisplayMapperComponent + class DisplayMapperComponentRequests + : public ComponentBus + { + public: + //! Load preconfigured preset for specific ODT mode + virtual void LoadPreset(OutputDeviceTransformType preset) = 0; + //! Set display mapper type + virtual void SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) = 0; + //! Set custom ACES parameters for ACES mapping, display mapper must be set to Aces to see the difference + virtual void SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) = 0; + }; + using DisplayMapperComponentRequestBus = EBus; + + //! DisplayMapperComponent can send out notifications on the DisplayMapperComponentNotifications + class DisplayMapperComponentNotifications : public ComponentBus + { + public: + //! Notifies that display mapper type changed + virtual void OntDisplayMapperOperationTypeUpdated([[maybe_unused]] const DisplayMapperOperationType& displayMapperOperationType) + { + } + + //! Notifies that ACES parameter overrides changed + virtual void OnAcesParameterOverridesUpdated([[maybe_unused]] const AcesParameterOverrides& acesParameterOverrides) + { + } + }; + using DisplayMapperComponentNotificationBus = EBus; + + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponent.cpp index 9642072cd2..b8d8336c30 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponent.cpp @@ -39,6 +39,5 @@ namespace AZ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common); } } - } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp index 0e283199e7..7831c0a4c6 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp @@ -76,6 +76,39 @@ namespace AZ return m_configuration; } + void DisplayMapperComponentController::LoadPreset(OutputDeviceTransformType preset) + { + AcesParameterOverrides propertyOverrides; + propertyOverrides.m_preset = preset; + propertyOverrides.m_overrideDefaults = true; + propertyOverrides.LoadPreset(); + SetAcesParameterOverrides(propertyOverrides); + } + + void DisplayMapperComponentController::SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) + { + if (m_configuration.m_displayMapperOperation != displayMapperOperationType) + { + m_configuration.m_displayMapperOperation = displayMapperOperationType; + OnConfigChanged(); + DisplayMapperComponentNotificationBus::Broadcast( + &DisplayMapperComponentNotificationBus::Handler::OntDisplayMapperOperationTypeUpdated, + m_configuration.m_displayMapperOperation); + } + } + + void DisplayMapperComponentController::SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) + { + m_configuration.m_acesParameterOverrides = parameterOverrides; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + DisplayMapperComponentNotificationBus::Broadcast( + &DisplayMapperComponentNotificationBus::Handler::OnAcesParameterOverridesUpdated, + m_configuration.m_acesParameterOverrides); + } + void DisplayMapperComponentController::OnConfigChanged() { // Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene. diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h index 3cc6a7e5d9..efa2070828 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h @@ -12,10 +12,12 @@ #pragma once + #include #include #include +#include #include #include @@ -24,7 +26,10 @@ namespace AZ { namespace Render { + struct AcesParameterOverrides; + class DisplayMapperComponentController final + : DisplayMapperComponentRequestBus::Handler { public: friend class EditorDisplayMapperComponent; @@ -43,6 +48,11 @@ namespace AZ void SetConfiguration(const DisplayMapperComponentConfig& config); const DisplayMapperComponentConfig& GetConfiguration() const; + //! DisplayMapperComponentRequestBus::Handler overrides... + void LoadPreset(OutputDeviceTransformType preset) override; + void SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) override; + void SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) override; + private: AZ_DISABLE_COPY(DisplayMapperComponentController); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp index 64cd450940..aadb0cc22b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp @@ -76,23 +76,32 @@ namespace AZ Edit::UIHandlers::Default, &AcesParameterOverrides::m_cinemaLimitsBlack, "Cinema Limit (black)", "Reference black luminance value") + ->Attribute(AZ::Edit::Attributes::Min, 0.02f) + ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_cinemaLimitsWhite) ->DataElement( Edit::UIHandlers::Default, &AcesParameterOverrides::m_cinemaLimitsWhite, "Cinema Limit (white)", "Reference white luminance value") + ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_cinemaLimitsBlack) + ->Attribute(AZ::Edit::Attributes::Max, 4000) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement( Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_minPoint, "Min Point (luminance)", "Linear extension below this") + ->Attribute(AZ::Edit::Attributes::Min, 0.002f) + ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_midPoint) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement( - Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_midPoint, "Mid Point (luminance)", - "Middle gray") + Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_midPoint, "Mid Point (luminance)", "Middle gray") + ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_minPoint) + ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_maxPoint) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement( Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_maxPoint, "Max Point (luminance)", "Linear extension above this") + ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_midPoint) + ->Attribute(AZ::Edit::Attributes::Max, 4000) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_public_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_public_files.cmake index 7b8d0a6e21..31a90e7ceb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_public_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_public_files.cmake @@ -36,6 +36,7 @@ set(FILES Include/AtomLyIntegration/CommonFeatures/PostProcess/Bloom/BloomComponentConfig.h Include/AtomLyIntegration/CommonFeatures/PostProcess/DepthOfField/DepthOfFieldBus.h Include/AtomLyIntegration/CommonFeatures/PostProcess/DepthOfField/DepthOfFieldComponentConfig.h + Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConfig.h Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConstants.h Include/AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlBus.h From 38819c630aa7313c49cb8073876b6f401df95efb Mon Sep 17 00:00:00 2001 From: mnaumov Date: Tue, 1 Jun 2021 15:34:01 -0700 Subject: [PATCH 02/45] PR feedback --- .../DisplayMapper/DisplayMapperComponentBus.h | 63 ++++- .../DisplayMapperComponentController.cpp | 231 +++++++++++++++++- .../DisplayMapperComponentController.h | 24 ++ .../EditorDisplayMapperComponent.cpp | 60 +++-- 4 files changed, 359 insertions(+), 19 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h index af57b69d3b..4a01f71325 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h @@ -30,8 +30,67 @@ namespace AZ virtual void LoadPreset(OutputDeviceTransformType preset) = 0; //! Set display mapper type virtual void SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) = 0; - //! Set custom ACES parameters for ACES mapping, display mapper must be set to Aces to see the difference + //! Get display mapper type + virtual DisplayMapperOperationType GetDisplayMapperOperationType() const = 0; + //! Set ACES parameter overrides for ACES mapping, display mapper must be set to Aces to see the difference virtual void SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) = 0; + //! Get ACES parameter overrides + virtual const AcesParameterOverrides& GetAcesParameterOverrides() const = 0; + + // Enable or disable ACES parameter overrides + virtual void SetOverrideAcesParameters(bool value) = 0; + // Check if ACES parameters are overriding default preset values + virtual bool GetOverrideAcesParameters() const = 0; + + // Set gamma adjustment to compensate for dim surround + virtual void SetAlterSurround(bool value) = 0; + // Get gamma adjustment to compensate for dim surround + virtual bool GetAlterSurround() const = 0; + + // Set desaturation to compensate for luminance difference + virtual void SetApplyDesaturation(bool value) = 0; + // Get desaturation to compensate for luminance difference + virtual bool GetApplyDesaturation() const = 0; + + // Set color appearance transform (CAT) from ACES white point to assumed observer adapted white point + virtual void SetApplyCATD60toD65(bool value) = 0; + // Get color appearance transform (CAT) from ACES white point to assumed observer adapted white point + virtual bool GetApplyCATD60toD65() const = 0; + + // Set reference black luminance value + virtual void SetCinemaLimitsBlack(float value) = 0; + // Get reference black luminance value + virtual float GetCinemaLimitsBlack() const = 0; + + // Set reference white luminance value + virtual void SetCinemaLimitsWhite(float value) = 0; + // Get reference white luminance value + virtual float GetCinemaLimitsWhite() const = 0; + + // Set min luminance value + virtual void SetMinPoint(float value) = 0; + // Get min luminance value + virtual float GetMinPoint() const = 0; + + // Set mid luminance value + virtual void SetMidPoint(float value) = 0; + // Get mid luminance value + virtual float GetMidPoint() const = 0; + + // Set max luminance value + virtual void SetMaxPoint(float value) = 0; + // Get max luminance value + virtual float GetMaxPoint() const = 0; + + // Set gamma adjustment value + virtual void SetSurroundGamma(float value) = 0; + // Get gamma adjustment value + virtual float GetSurroundGamma() const = 0; + + // Set optional gamma value that is applied as basic gamma curve OETF + virtual void SetGamma(float value) = 0; + // Get optional gamma value that is applied as basic gamma curve OETF + virtual float GetGamma() const = 0; }; using DisplayMapperComponentRequestBus = EBus; @@ -40,7 +99,7 @@ namespace AZ { public: //! Notifies that display mapper type changed - virtual void OntDisplayMapperOperationTypeUpdated([[maybe_unused]] const DisplayMapperOperationType& displayMapperOperationType) + virtual void OnDisplayMapperOperationTypeUpdated([[maybe_unused]] const DisplayMapperOperationType& displayMapperOperationType) { } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp index 7831c0a4c6..06c549f560 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp @@ -10,6 +10,8 @@ * */ +#include "AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h" + #include #include @@ -32,6 +34,69 @@ namespace AZ ->Version(0) ->Field("Configuration", &DisplayMapperComponentController::m_configuration); } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("DisplayMapperComponentRequestBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "render") + ->Attribute(AZ::Script::Attributes::Module, "render") + // LoadPreset + ->Event("LoadPreset", &DisplayMapperComponentRequestBus::Events::LoadPreset) + // DisplayMapperOperationType + ->Event("SetDisplayMapperOperationType", &DisplayMapperComponentRequestBus::Events::SetDisplayMapperOperationType) + ->Event("GetDisplayMapperOperationType", &DisplayMapperComponentRequestBus::Events::GetDisplayMapperOperationType) + ->VirtualProperty("DisplayMapperOperationType", "GetDisplayMapperOperationType", "SetDisplayMapperOperationType") + // AcesParameterOverrides + ->Event("SetAcesParameterOverrides", &DisplayMapperComponentRequestBus::Events::SetAcesParameterOverrides) + ->Event("GetAcesParameterOverrides", &DisplayMapperComponentRequestBus::Events::GetAcesParameterOverrides) + ->VirtualProperty("AcesParameterOverrides", "GetAcesParameterOverrides", "SetAcesParameterOverrides") + // OverrideAcesParameters + ->Event("SetOverrideAcesParameters", &DisplayMapperComponentRequestBus::Events::SetOverrideAcesParameters) + ->Event("GetOverrideAcesParameters", &DisplayMapperComponentRequestBus::Events::GetOverrideAcesParameters) + ->VirtualProperty("OverrideAcesParameters", "GetOverrideAcesParameters", "SetOverrideAcesParameters") + // AlterSurround + ->Event("SetAlterSurround", &DisplayMapperComponentRequestBus::Events::SetAlterSurround) + ->Event("GetAlterSurround", &DisplayMapperComponentRequestBus::Events::GetAlterSurround) + ->VirtualProperty("AlterSurround", "GetAlterSurround", "SetAlterSurround") + // ApplyDesaturation + ->Event("SetApplyDesaturation", &DisplayMapperComponentRequestBus::Events::SetApplyDesaturation) + ->Event("GetApplyDesaturation", &DisplayMapperComponentRequestBus::Events::GetApplyDesaturation) + ->VirtualProperty("ApplyDesaturation", "GetApplyDesaturation", "SetApplyDesaturation") + // ApplyCATD60toD65 + ->Event("SetApplyCATD60toD65", &DisplayMapperComponentRequestBus::Events::SetApplyCATD60toD65) + ->Event("GetApplyCATD60toD65", &DisplayMapperComponentRequestBus::Events::GetApplyCATD60toD65) + ->VirtualProperty("ApplyCATD60toD65", "GetApplyCATD60toD65", "SetApplyCATD60toD65") + // CinemaLimitsBlack + ->Event("SetCinemaLimitsBlack", &DisplayMapperComponentRequestBus::Events::SetCinemaLimitsBlack) + ->Event("GetCinemaLimitsBlack", &DisplayMapperComponentRequestBus::Events::GetCinemaLimitsBlack) + ->VirtualProperty("CinemaLimitsBlack", "GetCinemaLimitsBlack", "SetCinemaLimitsBlack") + // CinemaLimitsWhite + ->Event("SetCinemaLimitsWhite", &DisplayMapperComponentRequestBus::Events::SetCinemaLimitsWhite) + ->Event("GetCinemaLimitsWhite", &DisplayMapperComponentRequestBus::Events::GetCinemaLimitsWhite) + ->VirtualProperty("CinemaLimitsWhite", "GetCinemaLimitsWhite", "SetCinemaLimitsWhite") + // MinPoint + ->Event("SetMinPoint", &DisplayMapperComponentRequestBus::Events::SetMinPoint) + ->Event("GetMinPoint", &DisplayMapperComponentRequestBus::Events::GetMinPoint) + ->VirtualProperty("MinPoint", "GetMinPoint", "SetMinPoint") + // MidPoint + ->Event("SetMidPoint", &DisplayMapperComponentRequestBus::Events::SetMidPoint) + ->Event("GetMidPoint", &DisplayMapperComponentRequestBus::Events::GetMidPoint) + ->VirtualProperty("MidPoint", "GetMidPoint", "SetMidPoint") + // MaxPoint + ->Event("SetMaxPoint", &DisplayMapperComponentRequestBus::Events::SetMaxPoint) + ->Event("GetMaxPoint", &DisplayMapperComponentRequestBus::Events::GetMaxPoint) + ->VirtualProperty("MaxPoint", "GetMaxPoint", "SetMaxPoint") + // SurroundGamma + ->Event("SetSurroundGamma", &DisplayMapperComponentRequestBus::Events::SetSurroundGamma) + ->Event("GetSurroundGamma", &DisplayMapperComponentRequestBus::Events::GetSurroundGamma) + ->VirtualProperty("SurroundGamma", "GetSurroundGamma", "SetSurroundGamma") + // Gamma + ->Event("SetGamma", &DisplayMapperComponentRequestBus::Events::SetGamma) + ->Event("GetGamma", &DisplayMapperComponentRequestBus::Events::GetGamma) + ->VirtualProperty("Gamma", "GetGamma", "SetGamma") + ; + } } void DisplayMapperComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) @@ -92,11 +157,16 @@ namespace AZ m_configuration.m_displayMapperOperation = displayMapperOperationType; OnConfigChanged(); DisplayMapperComponentNotificationBus::Broadcast( - &DisplayMapperComponentNotificationBus::Handler::OntDisplayMapperOperationTypeUpdated, + &DisplayMapperComponentNotificationBus::Handler::OnDisplayMapperOperationTypeUpdated, m_configuration.m_displayMapperOperation); } } + DisplayMapperOperationType DisplayMapperComponentController::GetDisplayMapperOperationType() const + { + return m_configuration.m_displayMapperOperation; + } + void DisplayMapperComponentController::SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) { m_configuration.m_acesParameterOverrides = parameterOverrides; @@ -109,6 +179,165 @@ namespace AZ m_configuration.m_acesParameterOverrides); } + const AcesParameterOverrides& DisplayMapperComponentController::GetAcesParameterOverrides() const + { + return m_configuration.m_acesParameterOverrides; + } + + void DisplayMapperComponentController::SetOverrideAcesParameters(bool value) + { + m_configuration.m_acesParameterOverrides.m_overrideDefaults = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + bool DisplayMapperComponentController::GetOverrideAcesParameters() const + { + return m_configuration.m_acesParameterOverrides.m_overrideDefaults; + } + + void DisplayMapperComponentController::SetAlterSurround(bool value) + { + m_configuration.m_acesParameterOverrides.m_alterSurround = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + bool DisplayMapperComponentController::GetAlterSurround() const + { + return m_configuration.m_acesParameterOverrides.m_alterSurround; + } + + void DisplayMapperComponentController::SetApplyDesaturation(bool value) + { + m_configuration.m_acesParameterOverrides.m_applyDesaturation = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + bool DisplayMapperComponentController::GetApplyDesaturation() const + { + return m_configuration.m_acesParameterOverrides.m_applyDesaturation; + } + + void DisplayMapperComponentController::SetApplyCATD60toD65(bool value) + { + m_configuration.m_acesParameterOverrides.m_applyCATD60toD65 = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + bool DisplayMapperComponentController::GetApplyCATD60toD65() const + { + return m_configuration.m_acesParameterOverrides.m_applyCATD60toD65; + } + + void DisplayMapperComponentController::SetCinemaLimitsBlack(float value) + { + m_configuration.m_acesParameterOverrides.m_cinemaLimitsBlack = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetCinemaLimitsBlack() const + { + return m_configuration.m_acesParameterOverrides.m_cinemaLimitsBlack; + } + + void DisplayMapperComponentController::SetCinemaLimitsWhite(float value) + { + m_configuration.m_acesParameterOverrides.m_cinemaLimitsWhite = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetCinemaLimitsWhite() const + { + return m_configuration.m_acesParameterOverrides.m_cinemaLimitsWhite; + } + + void DisplayMapperComponentController::SetMinPoint(float value) + { + m_configuration.m_acesParameterOverrides.m_minPoint = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetMinPoint() const + { + return m_configuration.m_acesParameterOverrides.m_minPoint; + } + + void DisplayMapperComponentController::SetMidPoint(float value) + { + m_configuration.m_acesParameterOverrides.m_midPoint = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetMidPoint() const + { + return m_configuration.m_acesParameterOverrides.m_midPoint; + } + + void DisplayMapperComponentController::SetMaxPoint(float value) + { + m_configuration.m_acesParameterOverrides.m_maxPoint = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetMaxPoint() const + { + return m_configuration.m_acesParameterOverrides.m_maxPoint; + } + + void DisplayMapperComponentController::SetSurroundGamma(float value) + { + m_configuration.m_acesParameterOverrides.m_surroundGamma = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetSurroundGamma() const + { + return m_configuration.m_acesParameterOverrides.m_surroundGamma; + } + + void DisplayMapperComponentController::SetGamma(float value) + { + m_configuration.m_acesParameterOverrides.m_gamma = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetGamma() const + { + return m_configuration.m_acesParameterOverrides.m_gamma; + } + void DisplayMapperComponentController::OnConfigChanged() { // Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene. diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h index efa2070828..412bdc8524 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h @@ -51,7 +51,31 @@ namespace AZ //! DisplayMapperComponentRequestBus::Handler overrides... void LoadPreset(OutputDeviceTransformType preset) override; void SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) override; + DisplayMapperOperationType GetDisplayMapperOperationType() const override; void SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) override; + const AcesParameterOverrides& GetAcesParameterOverrides() const override; + void SetOverrideAcesParameters(bool value) override; + bool GetOverrideAcesParameters() const override; + void SetAlterSurround(bool value) override; + bool GetAlterSurround() const override; + void SetApplyDesaturation(bool value) override; + bool GetApplyDesaturation() const override; + void SetApplyCATD60toD65(bool value) override; + bool GetApplyCATD60toD65() const override; + void SetCinemaLimitsBlack(float value) override; + float GetCinemaLimitsBlack() const override; + void SetCinemaLimitsWhite(float value) override; + float GetCinemaLimitsWhite() const override; + void SetMinPoint(float value) override; + float GetMinPoint() const override; + void SetMidPoint(float value) override; + float GetMidPoint() const override; + void SetMaxPoint(float value) override; + float GetMaxPoint() const override; + void SetSurroundGamma(float value) override; + float GetSurroundGamma() const override; + void SetGamma(float value) override; + float GetGamma() const override; private: AZ_DISABLE_COPY(DisplayMapperComponentController); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp index aadb0cc22b..4a03c6f712 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp @@ -54,63 +54,89 @@ namespace AZ ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + // m_overrideDefaults ->DataElement( AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_overrideDefaults, "Override Defaults", "When enabled allows parameter overrides for ACES configuration") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + // m_alterSurround ->DataElement( AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_alterSurround, "Alter Surround", "Apply gamma adjustment to compensate for dim surround") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + + // m_applyDesaturation ->DataElement( AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_applyDesaturation, "Alter Desaturation", "Apply desaturation to compensate for luminance difference") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + + // m_applyCATD60toD65 ->DataElement( AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_applyCATD60toD65, "Alter CAT D60 to D65", "Apply Color appearance transform (CAT) from ACES white point to assumed observer adapted white point") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - + + // m_cinemaLimitsBlack ->DataElement( - Edit::UIHandlers::Default, &AcesParameterOverrides::m_cinemaLimitsBlack, + Edit::UIHandlers::Slider, &AcesParameterOverrides::m_cinemaLimitsBlack, "Cinema Limit (black)", "Reference black luminance value") ->Attribute(AZ::Edit::Attributes::Min, 0.02f) ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_cinemaLimitsWhite) + ->Attribute(AZ::Edit::Attributes::Step, 0.005f) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + + // m_cinemaLimitsWhite ->DataElement( - Edit::UIHandlers::Default, &AcesParameterOverrides::m_cinemaLimitsWhite, + Edit::UIHandlers::Slider, &AcesParameterOverrides::m_cinemaLimitsWhite, "Cinema Limit (white)", "Reference white luminance value") ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_cinemaLimitsBlack) - ->Attribute(AZ::Edit::Attributes::Max, 4000) + ->Attribute(AZ::Edit::Attributes::Max, 4000.f) + ->Attribute(AZ::Edit::Attributes::Step, 0.005f) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + // m_minPoint ->DataElement( - Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_minPoint, "Min Point (luminance)", + Edit::UIHandlers::Slider, &AcesParameterOverrides::m_minPoint, "Min Point (luminance)", "Linear extension below this") ->Attribute(AZ::Edit::Attributes::Min, 0.002f) ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_midPoint) - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement( - Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_midPoint, "Mid Point (luminance)", "Middle gray") + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) + + // m_midPoint + ->DataElement(Edit::UIHandlers::Slider, &AcesParameterOverrides::m_midPoint, + "Mid Point (luminance)", "Middle gray") ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_minPoint) ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_maxPoint) - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) + + // m_maxPoint ->DataElement( - Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_maxPoint, "Max Point (luminance)", + Edit::UIHandlers::Slider, &AcesParameterOverrides::m_maxPoint, "Max Point (luminance)", "Linear extension above this") ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_midPoint) - ->Attribute(AZ::Edit::Attributes::Max, 4000) + ->Attribute(AZ::Edit::Attributes::Max, 4000.f) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) + + // m_surroundGamma + ->DataElement( + AZ::Edit::UIHandlers::Slider, &AcesParameterOverrides::m_surroundGamma, "Surround Gamma", + "Gamma adjustment to be applied to compensate for the condition of the viewing environment") + ->Attribute(AZ::Edit::Attributes::Min, 0.6f) + ->Attribute(AZ::Edit::Attributes::Max, 1.2f) + ->Attribute(AZ::Edit::Attributes::Step, 0.005f) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + // m_gamma ->DataElement( - AZ::Edit::UIHandlers::Default, &AcesParameterOverrides::m_surroundGamma, "Surround Gamma", - "Gamma adjustment to be applied to compensate for the condition of the viewing environment") - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement( - AZ::Edit::UIHandlers::Default, &AcesParameterOverrides::m_gamma, "Gamma", + AZ::Edit::UIHandlers::Slider, &AcesParameterOverrides::m_gamma, "Gamma", "Optional gamma value that is applied as basic gamma curve OETF") + ->Attribute(AZ::Edit::Attributes::Min, 0.2f) + ->Attribute(AZ::Edit::Attributes::Max, 4.0f) + ->Attribute(AZ::Edit::Attributes::Step, 0.005f) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) // Load preset group @@ -154,6 +180,8 @@ namespace AZ if (auto behaviorContext = azrtti_cast(context)) { + behaviorContext->Class()->RequestBus("DisplayMapperComponentRequestBus"); + behaviorContext->ConstantProperty("EditorDisplayMapperComponentTypeId", BehaviorConstant(Uuid(EditorDisplayMapperComponentTypeId))) ->Attribute(AZ::Script::Attributes::Module, "render") ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation); From a1b8d1233cb75a330adfd260ad85c827f163f84d Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 11:28:22 -0700 Subject: [PATCH 03/45] [cpack_installer] initial work for installer Jenkins jobs --- .../build/Platform/Windows/build_config.json | 15 ++++++++ .../Windows/build_installer_windows.cmd | 22 +++++++++++ .../build/Platform/Windows/build_windows.cmd | 9 +++++ .../Platform/Windows/installer_windows.cmd | 38 +++++++++++++++++++ .../Platform/Windows/install_utiltools.ps1 | 3 ++ 5 files changed, 87 insertions(+) create mode 100644 scripts/build/Platform/Windows/build_installer_windows.cmd create mode 100644 scripts/build/Platform/Windows/installer_windows.cmd diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index 38cd7d6ad8..b0d16f1fb6 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -306,6 +306,21 @@ "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" } }, + "windows_installer": { + "TAGS": [ + "package" + ], + "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", + "CMAKE_INCLUDE_WIX": "True", + "CMAKE_LY_PROJECTS": "", + "CMAKE_TARGET": "ALL_BUILD", + "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" + } + }, "project_enginesource_profile_vs2019": { "TAGS": [ "project" diff --git a/scripts/build/Platform/Windows/build_installer_windows.cmd b/scripts/build/Platform/Windows/build_installer_windows.cmd new file mode 100644 index 0000000000..0d50f4b57a --- /dev/null +++ b/scripts/build/Platform/Windows/build_installer_windows.cmd @@ -0,0 +1,22 @@ +@ECHO OFF +REM +REM All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +REM its licensors. +REM +REM For complete copyright and license terms please see the LICENSE at the root of this +REM distribution (the "License"). All use of this software is governed by the License, +REM or, if provided, by the license below or the license accompanying this file. Do not +REM remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +REM + +CALL "%~dp0build_windows.cmd" +IF NOT %ERRORLEVEL%==0 GOTO :error + +CALL "%~dp0installer_windows.cmd" +IF NOT %ERRORLEVEL%==0 GOTO :error + +EXIT /b 0 + +:error +EXIT /b 1 \ No newline at end of file diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index 3e995e1905..109db3438e 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -38,6 +38,15 @@ IF NOT EXIST %TMP% ( REM Compute half the amount of processors so some jobs can run SET /a HALF_PROCESSORS = NUMBER_OF_PROCESSORS / 2 +IF %CMAKE_INCLUDE_WIX%=="True" ( + REM Explicitly enable wix via command line arg for forensic logging + SET EXTRA_CMAKE_OPTIONS=%EXTRA_CMAKE_OPTIONS% -DLY_WIX_PATH="%WIX%" +) +ELSE ( + REM Disable implicit enabling of windows packing by clearing out the wix variable + SET WIX= +) + SET LAST_CONFIGURE_CMD_FILE=ci_last_configure_cmd.txt SET CONFIGURE_CMD=cmake %SOURCE_DIRECTORY% %CMAKE_OPTIONS% %EXTRA_CMAKE_OPTIONS% -DLY_3RDPARTY_PATH="%LY_3RDPARTY_PATH%" -DLY_PROJECTS=%CMAKE_LY_PROJECTS% IF NOT EXIST CMakeCache.txt ( diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd new file mode 100644 index 0000000000..c613f0a1e3 --- /dev/null +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -0,0 +1,38 @@ +@ECHO OFF +REM +REM All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +REM its licensors. +REM +REM For complete copyright and license terms please see the LICENSE at the root of this +REM distribution (the "License"). All use of this software is governed by the License, +REM or, if provided, by the license below or the license accompanying this file. Do not +REM remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +REM + +SETLOCAL EnableDelayedExpansion + +CALL %~dp0env_windows.cmd + +IF NOT EXIST %OUTPUT_DIRECTORY% ( + ECHO [ci_build] Error: $OUTPUT_DIRECTORY was not found + GOTO :error +) +PUSHD %OUTPUT_DIRECTORY% + +REM Override the temporary directory used by wix to the EBS volume +SET "WIX_TEMP=!WORKSPACE!/temp/wix" + +REM Run cpack +ECHO [ci_build] cpack -C %CONFIGURATION% +cpack -C %CONFIGURATION% +IF NOT %ERRORLEVEL%==0 GOTO :popd_error + +POPD +EXIT /b 0 + +:popd_error +POPD + +:error +EXIT /b 1 \ No newline at end of file diff --git a/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 b/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 index 4e3695d35d..35ae04cc09 100644 --- a/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 +++ b/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 @@ -29,3 +29,6 @@ choco install corretto8jdk -y --ia INSTALLDIR="c:\jdk8" # Custom directory to ha # Install CMake choco install cmake -y --installargs 'ADD_CMAKE_TO_PATH=System' + +# Install WIX +choco install wixtoolset -y From ee0ecc2fa03b73cb95e3987d56a63441cfc8fe0a Mon Sep 17 00:00:00 2001 From: mnaumov Date: Wed, 2 Jun 2021 11:49:08 -0700 Subject: [PATCH 04/45] [ATOM-15711] Changing thumbmail sphere to polar sphere --- Gems/Atom/Feature/Common/Assets/Models/sphere.fbx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Models/sphere.fbx b/Gems/Atom/Feature/Common/Assets/Models/sphere.fbx index 5c8f550c8c..eb02c68394 100644 --- a/Gems/Atom/Feature/Common/Assets/Models/sphere.fbx +++ b/Gems/Atom/Feature/Common/Assets/Models/sphere.fbx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a476e99b55cf2a76fef6775c5a57dad29f8ffcb942c625bab04c89051a72a560 -size 62626 +oid sha256:838830c99f344f5b68e5e85c9bc52751350caf48e662c9c2b767ab77039bbd8f +size 103472 From cfd06f2e4a46869052dd5d6e5baee03d21860d35 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 13:10:11 -0700 Subject: [PATCH 05/45] [cpack_installer] added check for desired cmake version to be at least greater than minimum required plus minor cleanup --- cmake/Packaging.cmake | 10 ++++++++-- cmake/Platform/Windows/Packaging_windows.cmake | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 84bad13687..e7136eab12 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -51,6 +51,12 @@ if(NOT CPACK_GENERATOR) return() endif() +if(${CPACK_DESIRED_CMAKE_VERSION} VERSION_LESS ${CMAKE_MINIMUM_REQUIRED_VERSION}) + message(FATAL_ERROR + "The desired version of CMake to be included in the package is " + "is below the minium required version of CMake to run") +endif() + # pull down the desired copy of CMake so it can be included in the package if(NOT (CPACK_CMAKE_PACKAGE_FILE AND CPACK_CMAKE_PACKAGE_HASH)) message(FATAL_ERROR @@ -67,7 +73,7 @@ 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 "Ensuring CMake ${CPACK_DESIRED_CMAKE_VERSION} is available for packaging...") +message(STATUS "Downloading CMake ${CPACK_DESIRED_CMAKE_VERSION} for packaging...") download_file( URL ${_package_url} TARGET_FILE ${_cmake_package_dest} @@ -77,7 +83,7 @@ download_file( list(GET _results 0 _status_code) if (${_status_code} EQUAL 0 AND EXISTS ${_cmake_package_dest}) - message(STATUS "-> Package found and verified!") + message(STATUS "Package found and verified!") else() file(REMOVE ${_cmake_package_dest}) list(REMOVE_AT _results 0) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index db9c7fc906..5210c24e7b 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -12,7 +12,7 @@ set(LY_WIX_PATH "" CACHE PATH "Path to the WiX install path") if(LY_WIX_PATH) - file(TO_CMAKE_PATH ${LY_QTIFW_PATH} CPACK_WIX_ROOT) + file(TO_CMAKE_PATH ${LY_WIX_PATH} CPACK_WIX_ROOT) elseif(DEFINED ENV{WIX}) file(TO_CMAKE_PATH $ENV{WIX} CPACK_WIX_ROOT) endif() @@ -26,7 +26,7 @@ else() return() endif() -set(CPACK_GENERATOR "WIX") +set(CPACK_GENERATOR WIX) set(_cmake_package_name "cmake-${CPACK_DESIRED_CMAKE_VERSION}-windows-x86_64") set(CPACK_CMAKE_PACKAGE_FILE "${_cmake_package_name}.zip") From 12cdaed03e0c968630c4b27d25d86cdeede3c389 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 13:58:37 -0700 Subject: [PATCH 06/45] [cpack_installer] updated installer icon/logo --- cmake/Platform/Windows/Packaging/product_icon.ico | 4 ++-- cmake/Platform/Windows/Packaging/product_logo.png | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/Platform/Windows/Packaging/product_icon.ico b/cmake/Platform/Windows/Packaging/product_icon.ico index 0680ceea19..e7b77c35bf 100644 --- a/cmake/Platform/Windows/Packaging/product_icon.ico +++ b/cmake/Platform/Windows/Packaging/product_icon.ico @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c042fce57915fc749abc7b37de765fd697c3c4d7de045a3d44805aa0ce29901a -size 107016 +oid sha256:d717f77fe01f45df934a61bbc215e5322447d21e16f3cebcf2a02f148178f266 +size 106449 diff --git a/cmake/Platform/Windows/Packaging/product_logo.png b/cmake/Platform/Windows/Packaging/product_logo.png index d5fd60ffb8..ac9c06f8f1 100644 --- a/cmake/Platform/Windows/Packaging/product_logo.png +++ b/cmake/Platform/Windows/Packaging/product_logo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac0348c906c91de864cba91c0231b4794d8a00fafa630d13f2232351b90aa59b +oid sha256:8c804a6be619b9f35cad46eab30b94def7a4ac7142a92cb3f7c78a659381d834 size 11074 From 4b40f23d0b63cdf5b75188000c843e08c168c139 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 14:06:27 -0700 Subject: [PATCH 07/45] [cpack_installer] couple small fixes to installer Jenkins scripts --- scripts/build/Platform/Windows/build_windows.cmd | 5 ++--- scripts/build/Platform/Windows/installer_windows.cmd | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index 109db3438e..a2f42b75cf 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -38,11 +38,10 @@ IF NOT EXIST %TMP% ( REM Compute half the amount of processors so some jobs can run SET /a HALF_PROCESSORS = NUMBER_OF_PROCESSORS / 2 -IF %CMAKE_INCLUDE_WIX%=="True" ( +IF "%CMAKE_INCLUDE_WIX%"=="True" ( REM Explicitly enable wix via command line arg for forensic logging SET EXTRA_CMAKE_OPTIONS=%EXTRA_CMAKE_OPTIONS% -DLY_WIX_PATH="%WIX%" -) -ELSE ( +) ELSE ( REM Disable implicit enabling of windows packing by clearing out the wix variable SET WIX= ) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index c613f0a1e3..e8ce10ff14 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -22,6 +22,9 @@ PUSHD %OUTPUT_DIRECTORY% REM Override the temporary directory used by wix to the EBS volume SET "WIX_TEMP=!WORKSPACE!/temp/wix" +IF NOT EXIST "%WIX_TEMP%" ( + MKDIR %WIX_TEMP% +) REM Run cpack ECHO [ci_build] cpack -C %CONFIGURATION% From c6e4e3ed1fd549d88e27a0aac254ec3ab267bc98 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 14:57:18 -0700 Subject: [PATCH 08/45] [cpack_installer] few more small fixes to installer Jenkins scripts --- scripts/build/Platform/Windows/build_windows.cmd | 2 +- scripts/build/build_node/Platform/Windows/install_utiltools.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index a2f42b75cf..799e6828b2 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -40,7 +40,7 @@ SET /a HALF_PROCESSORS = NUMBER_OF_PROCESSORS / 2 IF "%CMAKE_INCLUDE_WIX%"=="True" ( REM Explicitly enable wix via command line arg for forensic logging - SET EXTRA_CMAKE_OPTIONS=%EXTRA_CMAKE_OPTIONS% -DLY_WIX_PATH="%WIX%" + SET CMAKE_OPTIONS=%CMAKE_OPTIONS% -DLY_WIX_PATH="%WIX%" ) ELSE ( REM Disable implicit enabling of windows packing by clearing out the wix variable SET WIX= diff --git a/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 b/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 index 35ae04cc09..050e446f52 100644 --- a/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 +++ b/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 @@ -30,5 +30,5 @@ choco install corretto8jdk -y --ia INSTALLDIR="c:\jdk8" # Custom directory to ha # Install CMake choco install cmake -y --installargs 'ADD_CMAKE_TO_PATH=System' -# Install WIX +# Install Windows Installer XML toolkit (WiX) choco install wixtoolset -y From 134258c18acff77588b7f57d8200d069144ecc2a Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 15:03:26 -0700 Subject: [PATCH 09/45] [cpack_installer] add trailing newline to some new files --- scripts/build/Platform/Windows/build_installer_windows.cmd | 2 +- scripts/build/Platform/Windows/installer_windows.cmd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Platform/Windows/build_installer_windows.cmd b/scripts/build/Platform/Windows/build_installer_windows.cmd index 0d50f4b57a..4f31fee085 100644 --- a/scripts/build/Platform/Windows/build_installer_windows.cmd +++ b/scripts/build/Platform/Windows/build_installer_windows.cmd @@ -19,4 +19,4 @@ IF NOT %ERRORLEVEL%==0 GOTO :error EXIT /b 0 :error -EXIT /b 1 \ No newline at end of file +EXIT /b 1 diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index e8ce10ff14..e3a60fee1c 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -38,4 +38,4 @@ EXIT /b 0 POPD :error -EXIT /b 1 \ No newline at end of file +EXIT /b 1 From 197241f16d4a7f0ec6bfc33af715d43aff93e6e8 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 15:40:41 -0700 Subject: [PATCH 10/45] [cpack_installer] fixed issue with cpack selection --- scripts/build/Platform/Windows/installer_windows.cmd | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index e3a60fee1c..824a461a4b 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -26,9 +26,17 @@ IF NOT EXIST "%WIX_TEMP%" ( MKDIR %WIX_TEMP% ) +REM Make sure we are using the CMake version of CPack and not the one that comes with chocolaty +IF "%LY_CMAKE_PATH%"=="" ( + for /f %%i in ('where cmake') do SET "CMAKE_EXE_PATH=%%i" + for %%F in ("%CMAKE_EXE_PATH%") do SET "CMAKE_INSTALL_PATH=%%~dpF" +) ELSE ( + SET "CMAKE_INSTALL_PATH=%LY_CMAKE_PATH%\" +) + REM Run cpack -ECHO [ci_build] cpack -C %CONFIGURATION% -cpack -C %CONFIGURATION% +ECHO [ci_build] "%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% +"%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% IF NOT %ERRORLEVEL%==0 GOTO :popd_error POPD From fd8cff6aecb2c93b93e6e09f9927feac563392c7 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 16:10:41 -0700 Subject: [PATCH 11/45] [cpack_installer] second attempt to fix cpack selection --- scripts/build/Platform/Windows/installer_windows.cmd | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index 824a461a4b..b1fecaa2cb 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -23,10 +23,11 @@ PUSHD %OUTPUT_DIRECTORY% REM Override the temporary directory used by wix to the EBS volume SET "WIX_TEMP=!WORKSPACE!/temp/wix" IF NOT EXIST "%WIX_TEMP%" ( - MKDIR %WIX_TEMP% + MKDIR "WIX_TEMP%" ) REM Make sure we are using the CMake version of CPack and not the one that comes with chocolaty +SET CMAKE_INSTALL_PATH= IF "%LY_CMAKE_PATH%"=="" ( for /f %%i in ('where cmake') do SET "CMAKE_EXE_PATH=%%i" for %%F in ("%CMAKE_EXE_PATH%") do SET "CMAKE_INSTALL_PATH=%%~dpF" @@ -34,6 +35,11 @@ IF "%LY_CMAKE_PATH%"=="" ( SET "CMAKE_INSTALL_PATH=%LY_CMAKE_PATH%\" ) +IF "%CMAKE_INSTALL_PATH%"=="" ( + ECHO [ci_build] CPack path not found + GOTO :popd_error +) + REM Run cpack ECHO [ci_build] "%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% "%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% From 201d6b1b72ec579c980c5e38d58fc354bfcc9a29 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 17:29:50 -0700 Subject: [PATCH 12/45] [cpack_installer] third attempt to fix cpack selection --- .../Platform/Windows/installer_windows.cmd | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index b1fecaa2cb..41cc21b35b 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -26,23 +26,29 @@ IF NOT EXIST "%WIX_TEMP%" ( MKDIR "WIX_TEMP%" ) -REM Make sure we are using the CMake version of CPack and not the one that comes with chocolaty -SET CMAKE_INSTALL_PATH= +REM Make sure we are using the CMake version of CPack and not the one that comes with chocolatey +SET CPACK_PATH= IF "%LY_CMAKE_PATH%"=="" ( - for /f %%i in ('where cmake') do SET "CMAKE_EXE_PATH=%%i" - for %%F in ("%CMAKE_EXE_PATH%") do SET "CMAKE_INSTALL_PATH=%%~dpF" + FOR /F %%i in ('where cpack') DO ( + REM The cpack in chocolatey expects a number supplied with --version so it will error + %%i --version > NUL + IF !ERRORLEVEL!==0 ( + SET "CPACK_PATH=%%i" + ) + ) ) ELSE ( - SET "CMAKE_INSTALL_PATH=%LY_CMAKE_PATH%\" + SET "CPACK_PATH=%LY_CMAKE_PATH%\cpack.exe" ) -IF "%CMAKE_INSTALL_PATH%"=="" ( - ECHO [ci_build] CPack path not found - GOTO :popd_error +ECHO [ci_build] "%CPACK_PATH%" --version +"%CPACK_PATH%" --version +IF ERRORLEVEL 1 ( + ECHO [ci_build] CPack not found! + exit /b 1 ) - REM Run cpack -ECHO [ci_build] "%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% -"%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% +ECHO [ci_build] "%CPACK_PATH%" -C %CONFIGURATION% +"%CPACK_PATH%" -C %CONFIGURATION% IF NOT %ERRORLEVEL%==0 GOTO :popd_error POPD From 01f3ba560819fcba0d3a5575510e597904cced4f Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 17:58:58 -0700 Subject: [PATCH 13/45] [cpack_installer] fourth attempt to fix cpack selection --- scripts/build/Platform/Windows/installer_windows.cmd | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index 41cc21b35b..ef284290f3 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -23,7 +23,7 @@ PUSHD %OUTPUT_DIRECTORY% REM Override the temporary directory used by wix to the EBS volume SET "WIX_TEMP=!WORKSPACE!/temp/wix" IF NOT EXIST "%WIX_TEMP%" ( - MKDIR "WIX_TEMP%" + MKDIR "%WIX_TEMP%" ) REM Make sure we are using the CMake version of CPack and not the one that comes with chocolatey @@ -40,15 +40,15 @@ IF "%LY_CMAKE_PATH%"=="" ( SET "CPACK_PATH=%LY_CMAKE_PATH%\cpack.exe" ) -ECHO [ci_build] "%CPACK_PATH%" --version -"%CPACK_PATH%" --version +ECHO [ci_build] "!CPACK_PATH!" --version +"!CPACK_PATH!" --version IF ERRORLEVEL 1 ( ECHO [ci_build] CPack not found! exit /b 1 ) -REM Run cpack -ECHO [ci_build] "%CPACK_PATH%" -C %CONFIGURATION% -"%CPACK_PATH%" -C %CONFIGURATION% + +ECHO [ci_build] "!CPACK_PATH!" -C %CONFIGURATION% +"!CPACK_PATH!" -C %CONFIGURATION% IF NOT %ERRORLEVEL%==0 GOTO :popd_error POPD From 9dbe596e400bbeac8fcecc34227821fceab378b1 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Wed, 2 Jun 2021 18:39:05 -0700 Subject: [PATCH 14/45] Added reflection probe cubemap quality levels --- .../Config/IBLSpecular.preset | 15 +- .../Config/IBLSpecularHigh.preset | 135 ++++++++++++++++++ .../Config/IBLSpecularLow.preset | 135 ++++++++++++++++++ .../Config/IBLSpecularVeryHigh.preset | 135 ++++++++++++++++++ .../Config/IBLSpecularVeryLow.preset | 135 ++++++++++++++++++ .../EditorReflectionProbeComponent.cpp | 20 ++- .../EditorReflectionProbeComponent.h | 1 + .../ReflectionProbeComponentController.cpp | 1 + .../ReflectionProbeComponentController.h | 24 ++++ 9 files changed, 595 insertions(+), 6 deletions(-) create mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset create mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset create mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset create mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset index d940f425c2..4f935c73ff 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset @@ -8,7 +8,8 @@ "Name": "IBLSpecular", "Description": "The input cubemap generates an IBL specular output cubemap.", "FileMasks": [ - "_iblspecularcm" + "_iblspecularcm", + "_iblspecularcm256" ], "SourceColor": "Linear", "DestColor": "Linear", @@ -34,7 +35,8 @@ "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", "FileMasks": [ - "_iblspecularcm" + "_iblspecularcm", + "_iblspecularcm256" ], "SourceColor": "Linear", "DestColor": "Linear", @@ -59,7 +61,8 @@ "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", "FileMasks": [ - "_iblspecularcm" + "_iblspecularcm", + "_iblspecularcm256" ], "SourceColor": "Linear", "DestColor": "Linear", @@ -84,7 +87,8 @@ "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", "FileMasks": [ - "_iblspecularcm" + "_iblspecularcm", + "_iblspecularcm256" ], "SourceColor": "Linear", "DestColor": "Linear", @@ -109,7 +113,8 @@ "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", "FileMasks": [ - "_iblspecularcm" + "_iblspecularcm", + "_iblspecularcm256" ], "SourceColor": "Linear", "DestColor": "Linear", diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset new file mode 100644 index 0000000000..ff4e143326 --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset @@ -0,0 +1,135 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "MultiplatformPresetSettings", + "ClassData": { + "DefaultPreset": { + "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", + "Name": "IBLSpecularHigh", + "Description": "The input cubemap generates an IBL specular output cubemap.", + "FileMasks": [ + "_iblspecularcm512" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 512, + "MaxTextureSize": 512, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "PlatformsPresets": { + "android": { + "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", + "Name": "IBLSpecularHigh", + "FileMasks": [ + "_iblspecularcm512" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 512, + "MaxTextureSize": 512, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "ios": { + "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", + "Name": "IBLSpecularHigh", + "FileMasks": [ + "_iblspecularcm512" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 512, + "MaxTextureSize": 512, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "mac": { + "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", + "Name": "IBLSpecularHigh", + "FileMasks": [ + "_iblspecularcm512" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 512, + "MaxTextureSize": 512, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "provo": { + "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", + "Name": "IBLSpecularHigh", + "FileMasks": [ + "_iblspecularcm512" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 512, + "MaxTextureSize": 512, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + } + } + } +} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset new file mode 100644 index 0000000000..ee9ddd6ac7 --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset @@ -0,0 +1,135 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "MultiplatformPresetSettings", + "ClassData": { + "DefaultPreset": { + "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", + "Name": "IBLSpecularLow", + "Description": "The input cubemap generates an IBL specular output cubemap.", + "FileMasks": [ + "_iblspecularcm128" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 128, + "MaxTextureSize": 128, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "PlatformsPresets": { + "android": { + "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", + "Name": "IBLSpecularLow", + "FileMasks": [ + "_iblspecularcm128" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 128, + "MaxTextureSize": 128, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "ios": { + "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", + "Name": "IBLSpecularLow", + "FileMasks": [ + "_iblspecularcm128" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 128, + "MaxTextureSize": 128, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "mac": { + "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", + "Name": "IBLSpecularLow", + "FileMasks": [ + "_iblspecularcm128" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 128, + "MaxTextureSize": 128, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "provo": { + "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", + "Name": "IBLSpecularLow", + "FileMasks": [ + "_iblspecularcm128" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 128, + "MaxTextureSize": 128, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + } + } + } +} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset new file mode 100644 index 0000000000..08d9416935 --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset @@ -0,0 +1,135 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "MultiplatformPresetSettings", + "ClassData": { + "DefaultPreset": { + "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", + "Name": "IBLSpecularVeryHigh", + "Description": "The input cubemap generates an IBL specular output cubemap.", + "FileMasks": [ + "_iblspecularcm1024" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 1024, + "MaxTextureSize": 1024, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "PlatformsPresets": { + "android": { + "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", + "Name": "IBLSpecularVeryHigh", + "FileMasks": [ + "_iblspecularcm1024" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 1024, + "MaxTextureSize": 1024, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "ios": { + "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", + "Name": "IBLSpecularVeryHigh", + "FileMasks": [ + "_iblspecularcm1024" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 1024, + "MaxTextureSize": 1024, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "mac": { + "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", + "Name": "IBLSpecularVeryHigh", + "FileMasks": [ + "_iblspecularcm1024" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 1024, + "MaxTextureSize": 1024, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "provo": { + "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", + "Name": "IBLSpecularVeryHigh", + "FileMasks": [ + "_iblspecularcm1024" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 1024, + "MaxTextureSize": 1024, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + } + } + } +} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset new file mode 100644 index 0000000000..c5c0788848 --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset @@ -0,0 +1,135 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "MultiplatformPresetSettings", + "ClassData": { + "DefaultPreset": { + "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", + "Name": "IBLSpecularVeryLow", + "Description": "The input cubemap generates an IBL specular output cubemap.", + "FileMasks": [ + "_iblspecularcm64" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 64, + "MaxTextureSize": 64, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "PlatformsPresets": { + "android": { + "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", + "Name": "IBLSpecularVeryLow", + "FileMasks": [ + "_iblspecularcm64" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 64, + "MaxTextureSize": 64, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "ios": { + "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", + "Name": "IBLSpecularVeryLow", + "FileMasks": [ + "_iblspecularcm64" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 64, + "MaxTextureSize": 64, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "mac": { + "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", + "Name": "IBLSpecularVeryLow", + "FileMasks": [ + "_iblspecularcm64" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 64, + "MaxTextureSize": 64, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "provo": { + "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", + "Name": "IBLSpecularVeryLow", + "FileMasks": [ + "_iblspecularcm64" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 64, + "MaxTextureSize": 64, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + } + } + } +} diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp index 7880d5e88c..f3932322b1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp @@ -39,6 +39,7 @@ namespace AZ serializeContext->Class() ->Version(2, ConvertToEditorRenderComponentAdapter<1>) ->Field("useBakedCubemap", &EditorReflectionProbeComponent::m_useBakedCubemap) + ->Field("bakedCubeMapQualityLevel", &EditorReflectionProbeComponent::m_bakedCubeMapQualityLevel) ->Field("bakedCubeMapRelativePath", &EditorReflectionProbeComponent::m_bakedCubeMapRelativePath) ->Field("authoredCubeMapAsset", &EditorReflectionProbeComponent::m_authoredCubeMapAsset) ; @@ -67,6 +68,13 @@ namespace AZ ->DataElement(AZ::Edit::UIHandlers::Default, &EditorReflectionProbeComponent::m_useBakedCubemap, "Use Baked Cubemap", "Selects between a cubemap that captures the environment at location in the scene or a preauthored cubemap") ->Attribute(AZ::Edit::Attributes::ChangeValidate, &EditorReflectionProbeComponent::OnUseBakedCubemapValidate) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::OnUseBakedCubemapChanged) + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorReflectionProbeComponent::m_bakedCubeMapQualityLevel, "Baked Cubemap Quality", "Resolution of the baked cubemap") + ->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting) + ->EnumAttribute(BakedCubeMapQualityLevel::VeryLow, "Very Low") + ->EnumAttribute(BakedCubeMapQualityLevel::Low, "Low") + ->EnumAttribute(BakedCubeMapQualityLevel::Medium, "Medium") + ->EnumAttribute(BakedCubeMapQualityLevel::High, "High") + ->EnumAttribute(BakedCubeMapQualityLevel::VeryHigh, "Very High") ->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorReflectionProbeComponent::m_bakedCubeMapRelativePath, "Baked Cubemap Path", "Baked Cubemap Path") ->Attribute(AZ::Edit::Attributes::ReadOnly, true) ->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting) @@ -332,6 +340,12 @@ namespace AZ // clear it to force the generation of a new filename cubeMapRelativePath.clear(); } + + // if the quality level changed we need to generate a new filename + if (m_controller.m_configuration.m_bakedCubeMapQualityLevel != m_bakedCubeMapQualityLevel) + { + cubeMapRelativePath.clear(); + } } // build a new cubemap path if necessary @@ -345,7 +359,10 @@ namespace AZ AZStd::string uuidString; uuid.ToString(uuidString); - cubeMapRelativePath = "ReflectionProbes/" + entity->GetName() + "_" + uuidString + "_iblspecularcm.dds"; + // determine the filemask suffix from the cubemap quality level setting + AZStd::string fileSuffix = BakedCubeMapFileSuffixes[aznumeric_cast(m_bakedCubeMapQualityLevel)]; + + cubeMapRelativePath = "ReflectionProbes/" + entity->GetName() + "_" + uuidString + fileSuffix; // replace any invalid filename characters auto invalidCharacters = [](char letter) @@ -384,6 +401,7 @@ namespace AZ // save the relative source path in the configuration AzToolsFramework::ScopedUndoBatch undoBatch("Cubemap path changed."); m_controller.m_configuration.m_bakedCubeMapRelativePath = cubeMapRelativePath; + m_controller.m_configuration.m_bakedCubeMapQualityLevel = m_bakedCubeMapQualityLevel; SetDirty(); // update UI cubemap path display diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h index 23fd391818..bc45eae11b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h @@ -77,6 +77,7 @@ namespace AZ // UI settings // the user can select between a baked cubemap or an authored cubemap asset bool m_useBakedCubemap = true; + BakedCubeMapQualityLevel m_bakedCubeMapQualityLevel = BakedCubeMapQualityLevel::Medium; AZStd::string m_bakedCubeMapRelativePath; Data::Asset m_bakedCubeMapAsset; Data::Asset m_authoredCubeMapAsset; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp index 9b0ff29bb8..873810c016 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp @@ -46,6 +46,7 @@ namespace AZ ->Field("InnerLength", &ReflectionProbeComponentConfig::m_innerLength) ->Field("InnerWidth", &ReflectionProbeComponentConfig::m_innerWidth) ->Field("UseBakedCubemap", &ReflectionProbeComponentConfig::m_useBakedCubemap) + ->Field("BakedCubemapQualityLevel", &ReflectionProbeComponentConfig::m_bakedCubeMapQualityLevel) ->Field("BakedCubeMapRelativePath", &ReflectionProbeComponentConfig::m_bakedCubeMapRelativePath) ->Field("BakedCubeMapAsset", &ReflectionProbeComponentConfig::m_bakedCubeMapAsset) ->Field("AuthoredCubeMapAsset", &ReflectionProbeComponentConfig::m_authoredCubeMapAsset) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h index 0a57fde882..97a7fbebb4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h @@ -24,6 +24,29 @@ namespace AZ { namespace Render { + enum class BakedCubeMapQualityLevel : uint32_t + { + VeryLow, // 64 + Low, // 128 + Medium, // 256 + High, // 512 + VeryHigh, // 1024 + + Count + }; + + static const char* BakedCubeMapFileSuffixes[] = + { + "_iblspecularcm64.dds", + "_iblspecularcm128.dds", + "_iblspecularcm256.dds", + "_iblspecularcm512.dds", + "_iblspecularcm1024.dds" + }; + + static_assert(AZ_ARRAY_SIZE(BakedCubeMapFileSuffixes) == aznumeric_cast(BakedCubeMapQualityLevel::Count), + "BakedCubeMapFileSuffixes must have the same number of entries as BakedCubeMapQualityLevel"); + class ReflectionProbeComponentConfig final : public AZ::ComponentConfig { @@ -43,6 +66,7 @@ namespace AZ bool m_showVisualization = true; bool m_useBakedCubemap = true; + BakedCubeMapQualityLevel m_bakedCubeMapQualityLevel = BakedCubeMapQualityLevel::Medium; AZStd::string m_bakedCubeMapRelativePath; Data::Asset m_bakedCubeMapAsset; Data::Asset m_authoredCubeMapAsset; From 3f9811e498efdb07e9275a3395f201b65ce8aa0f Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 18:40:22 -0700 Subject: [PATCH 15/45] [cpack_installer] fifth attempt to fix cpack selection --- scripts/build/Platform/Windows/installer_windows.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index ef284290f3..73d1a3d88c 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -31,7 +31,7 @@ SET CPACK_PATH= IF "%LY_CMAKE_PATH%"=="" ( FOR /F %%i in ('where cpack') DO ( REM The cpack in chocolatey expects a number supplied with --version so it will error - %%i --version > NUL + "%%i" --version > NUL IF !ERRORLEVEL!==0 ( SET "CPACK_PATH=%%i" ) From c3df73bed8f4b052659086e69127e90ae794bb46 Mon Sep 17 00:00:00 2001 From: mnaumov Date: Wed, 2 Jun 2021 18:48:50 -0700 Subject: [PATCH 16/45] PR feedback and fixing TrackView --- .../DisplayMapperConfigurationDescriptor.cpp | 2 +- .../DisplayMapper/DisplayMapperComponentBus.h | 5 +++++ .../DisplayMapperComponentController.cpp | 20 +++++++++++++++++++ .../EditorDisplayMapperComponent.cpp | 5 ++--- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp index 0858381fc5..a064b61a1a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp @@ -96,7 +96,7 @@ namespace AZ ; serializeContext->Class() - ->Version(1) + ->Version(2) ->Field("Name", &DisplayMapperConfigurationDescriptor::m_name) ->Field("OperationType", &DisplayMapperConfigurationDescriptor::m_operationType) ->Field("LdrGradingLutEnabled", &DisplayMapperConfigurationDescriptor::m_ldrGradingLutEnabled) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h index 4a01f71325..448c6cd32a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h @@ -26,6 +26,11 @@ namespace AZ : public ComponentBus { public: + AZ_RTTI(AZ::Render::DisplayMapperComponentRequests, "{9E2E8AF5-1176-44B4-A461-E09867753349}"); + + /// Overrides the default AZ::EBusTraits handler policy to allow one listener only. + static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single; + //! Load preconfigured preset for specific ODT mode virtual void LoadPreset(OutputDeviceTransformType preset) = 0; //! Set display mapper type diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp index 06c549f560..30c0ac8b1d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp @@ -122,10 +122,14 @@ namespace AZ void DisplayMapperComponentController::Activate(EntityId entityId) { m_entityId = entityId; + + DisplayMapperComponentRequestBus::Handler::BusConnect(m_entityId); } void DisplayMapperComponentController::Deactivate() { + DisplayMapperComponentRequestBus::Handler::BusDisconnect(m_entityId); + m_postProcessInterface = nullptr; m_entityId.SetInvalid(); } @@ -186,6 +190,10 @@ namespace AZ void DisplayMapperComponentController::SetOverrideAcesParameters(bool value) { + if (m_configuration.m_acesParameterOverrides.m_overrideDefaults == value) + { + return; // prevents flickering when set via TrackView + } m_configuration.m_acesParameterOverrides.m_overrideDefaults = value; if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) { @@ -200,6 +208,10 @@ namespace AZ void DisplayMapperComponentController::SetAlterSurround(bool value) { + if (m_configuration.m_acesParameterOverrides.m_alterSurround != value) + { + return; // prevents flickering when set via TrackView + } m_configuration.m_acesParameterOverrides.m_alterSurround = value; if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) { @@ -214,6 +226,10 @@ namespace AZ void DisplayMapperComponentController::SetApplyDesaturation(bool value) { + if (m_configuration.m_acesParameterOverrides.m_applyDesaturation != value) + { + return; // prevents flickering when set via TrackView + } m_configuration.m_acesParameterOverrides.m_applyDesaturation = value; if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) { @@ -228,6 +244,10 @@ namespace AZ void DisplayMapperComponentController::SetApplyCATD60toD65(bool value) { + if (m_configuration.m_acesParameterOverrides.m_applyCATD60toD65 != value) + { + return; // prevents flickering when set via TrackView + } m_configuration.m_acesParameterOverrides.m_applyCATD60toD65 = value; if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp index 4a03c6f712..8b59cfc9ea 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp @@ -10,10 +10,9 @@ * */ -#include "Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h" - #include #include +#include namespace AZ { @@ -180,7 +179,7 @@ namespace AZ if (auto behaviorContext = azrtti_cast(context)) { - behaviorContext->Class()->RequestBus("DisplayMapperComponentRequestBus"); + behaviorContext->Class()->RequestBus("DisplayMapperComponentRequestBus"); behaviorContext->ConstantProperty("EditorDisplayMapperComponentTypeId", BehaviorConstant(Uuid(EditorDisplayMapperComponentTypeId))) ->Attribute(AZ::Script::Attributes::Module, "render") From b09f73378f3efc08f7fa775e1f49bd38b30f63f3 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 20:49:39 -0700 Subject: [PATCH 17/45] [cpack_installer] replaced LY_DEFAULT_INSTALL_COMPONENT with built-in CMAKE_INSTALL_DEFAULT_COMPONENT_NAME. updated stale references to ly_install_target_COMPONENT with a get_prop call --- cmake/3rdParty.cmake | 2 - cmake/Packaging.cmake | 4 +- cmake/Platform/Common/Install_common.cmake | 46 ++++++++-------------- 3 files changed, 19 insertions(+), 33 deletions(-) diff --git a/cmake/3rdParty.cmake b/cmake/3rdParty.cmake index eb11404237..ebf640af23 100644 --- a/cmake/3rdParty.cmake +++ b/cmake/3rdParty.cmake @@ -291,7 +291,6 @@ function(ly_install_external_target 3RDPARTY_ROOT_DIRECTORY) # Install the Find file to our /cmake directory install(FILES ${CMAKE_CURRENT_LIST_FILE} DESTINATION cmake - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # We only want to install external targets that are part of our source tree @@ -302,7 +301,6 @@ function(ly_install_external_target 3RDPARTY_ROOT_DIRECTORY) get_filename_component(rel_path ${rel_path} DIRECTORY) install(DIRECTORY ${3RDPARTY_ROOT_DIRECTORY} DESTINATION ${rel_path} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endif() diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index e7136eab12..1bcb251271 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -101,7 +101,7 @@ endif() install(FILES ${_cmake_package_dest} DESTINATION ./Tools/Redistributables/CMake - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) # IMPORTANT: required to be included AFTER setting all property overrides @@ -141,7 +141,7 @@ endfunction() # configure ALL components here ly_configure_cpack_component( - ${LY_DEFAULT_INSTALL_COMPONENT} REQUIRED + ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} REQUIRED DISPLAY_NAME "${PROJECT_NAME} Core" DESCRIPTION "${PROJECT_NAME} Headers, Libraries and Tools" ) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 710a8b266f..e0301bb914 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -11,7 +11,7 @@ set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise -ly_set(LY_DEFAULT_INSTALL_COMPONENT Core) +ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Core) file(RELATIVE_PATH runtime_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) @@ -27,6 +27,12 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) # De-alias target name ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) + # get the component ID. if the property isn't set for the target, fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME + get_target_property(install_componet ${TARGET_NAME} INSTALL_COMPONENT) + if("${install_componet}" STREQUAL "install_componet-NOTFOUND") + unset(install_componet) + endif() + # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. @@ -41,7 +47,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) unset(current_public_headers) install(DIRECTORY ${include_directory} DESTINATION ${include_location}/${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} FILES_MATCHING PATTERN *.h PATTERN *.hpp @@ -68,13 +74,13 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) TARGETS ${TARGET_NAME} ARCHIVE DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} LIBRARY DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} RUNTIME DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} ) # CMakeLists.txt file @@ -182,7 +188,7 @@ set_property(TARGET ${TARGET_NAME} file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" DESTINATION ${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} ) # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target @@ -239,9 +245,13 @@ function(ly_setup_subdirectory absolute_target_source_dir) "\n" "${CREATE_ALIASES_PLACEHOLDER}" ) + + # get the component ID. if the property isn't set for the directory, it will auto fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME + get_property(install_componet DIRECTORY ${absolute_target_source_dir} PROPERTY INSTALL_COMPONENT) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt" DESTINATION ${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} ) endfunction() @@ -262,7 +272,6 @@ function(ly_setup_cmake_install) install(DIRECTORY "${LY_ROOT_FOLDER}/cmake" DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} PATTERN "__pycache__" EXCLUDE REGEX "Findo3de.cmake" EXCLUDE REGEX "Platform\/.*\/BuiltInPackages_.*\.cmake" EXCLUDE @@ -290,7 +299,6 @@ function(ly_setup_cmake_install) "${LY_ROOT_FOLDER}/CMakeLists.txt" "${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json" DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Collect all Find files that were added with ly_add_external_target_path @@ -303,7 +311,6 @@ function(ly_setup_cmake_install) endforeach() install(FILES ${additional_find_files} DESTINATION cmake/3rdParty - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Findo3de.cmake file: we generate a different Findo3de.camke file than the one we have in cmake. This one is going to expose all @@ -320,7 +327,6 @@ function(ly_setup_cmake_install) configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake" DESTINATION cmake - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # BuiltInPackage_.cmake: since associations could happen in any cmake file across the engine. We collect @@ -340,7 +346,6 @@ function(ly_setup_cmake_install) ) install(FILES "${pal_builtin_file}" DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endfunction() @@ -362,7 +367,6 @@ endfunction() function(ly_copy source_file target_directory) file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) endfunction()" - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) unset(runtime_commands) @@ -408,7 +412,6 @@ endfunction()" list(REMOVE_DUPLICATES runtime_commands) list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file install(CODE "${runtime_commands_str}" - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endfunction() @@ -427,7 +430,6 @@ function(ly_setup_others) install(DIRECTORY "${LY_ROOT_FOLDER}/${dir}" DESTINATION ${install_path} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} PATTERN "__pycache__" EXCLUDE ) @@ -438,7 +440,6 @@ function(ly_setup_others) install(FILES ${o3de_scripts} DESTINATION ./scripts - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) install(DIRECTORY @@ -446,7 +447,6 @@ function(ly_setup_others) ${LY_ROOT_FOLDER}/scripts/project_manager ${LY_ROOT_FOLDER}/scripts/o3de DESTINATION ./scripts - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} PATTERN "__pycache__" EXCLUDE PATTERN "CMakeLists.txt" EXCLUDE PATTERN "tests" EXCLUDE @@ -454,7 +454,6 @@ function(ly_setup_others) install(DIRECTORY "${LY_ROOT_FOLDER}/python" DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} REGEX "downloaded_packages" EXCLUDE REGEX "runtime" EXCLUDE ) @@ -463,19 +462,16 @@ function(ly_setup_others) install(DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/Registry DESTINATION ./${runtime_output_directory}/${PAL_PLATFORM_NAME}/$ - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) install(DIRECTORY ${LY_ROOT_FOLDER}/Registry DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Engine Source Assets install(DIRECTORY ${LY_ROOT_FOLDER}/Assets DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Gem Source Assets and Registry @@ -495,7 +491,6 @@ function(ly_setup_others) # the "Assets" folder from being copied underneath the /Assets folder install(DIRECTORY ${gem_abs_assets_path} DESTINATION ${gem_assets_path} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endif() endforeach() @@ -511,7 +506,6 @@ function(ly_setup_others) get_filename_component(gem_relative_path ${gem_json_path} DIRECTORY) install(FILES ${gem_json_path} DESTINATION ${gem_relative_path} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endforeach() @@ -519,14 +513,12 @@ function(ly_setup_others) install(DIRECTORY ${LY_ROOT_FOLDER}/Gems/Atom/Asset/ImageProcessingAtom/Config DESTINATION Gems/Atom/Asset/ImageProcessingAtom - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Templates install(DIRECTORY ${LY_ROOT_FOLDER}/Templates DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Misc @@ -535,7 +527,6 @@ function(ly_setup_others) ${LY_ROOT_FOLDER}/LICENSE.txt ${LY_ROOT_FOLDER}/README.md DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endfunction() @@ -549,15 +540,12 @@ function(ly_setup_target_generator) ${LY_ROOT_FOLDER}/Code/LauncherUnified/LauncherProject.cpp ${LY_ROOT_FOLDER}/Code/LauncherUnified/StaticModules.in DESTINATION LauncherGenerator - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) install(DIRECTORY ${LY_ROOT_FOLDER}/Code/LauncherUnified/Platform DESTINATION LauncherGenerator - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) install(FILES ${LY_ROOT_FOLDER}/Code/LauncherUnified/FindLauncherGenerator.cmake DESTINATION cmake - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endfunction() From 5695681ed3518d3e7c4ab7ed3aad92c4bb01d422 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 21:03:41 -0700 Subject: [PATCH 18/45] [cpack_installer] fifth attempt to fix cpack selection --- scripts/build/Platform/Windows/installer_windows.cmd | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index 73d1a3d88c..c71b091de9 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -29,22 +29,25 @@ IF NOT EXIST "%WIX_TEMP%" ( REM Make sure we are using the CMake version of CPack and not the one that comes with chocolatey SET CPACK_PATH= IF "%LY_CMAKE_PATH%"=="" ( - FOR /F %%i in ('where cpack') DO ( + REM quote the paths from 'where' so we can properly tokenize ones in the list with spaces + FOR /F delims^=^"^ tokens^=1 %%i in ('where /F cpack') DO ( REM The cpack in chocolatey expects a number supplied with --version so it will error "%%i" --version > NUL IF !ERRORLEVEL!==0 ( SET "CPACK_PATH=%%i" + GOTO :run_cpack ) ) ) ELSE ( SET "CPACK_PATH=%LY_CMAKE_PATH%\cpack.exe" ) +:run_cpack ECHO [ci_build] "!CPACK_PATH!" --version "!CPACK_PATH!" --version IF ERRORLEVEL 1 ( ECHO [ci_build] CPack not found! - exit /b 1 + GOTO :popd_error ) ECHO [ci_build] "!CPACK_PATH!" -C %CONFIGURATION% From 602dd01434848ad04e32123e1dbd6d0aeb717824 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 22:02:11 -0700 Subject: [PATCH 19/45] [cpack_installer] fixed typo in error message --- cmake/Packaging.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 1bcb251271..e2aa0f9348 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -54,7 +54,7 @@ endif() if(${CPACK_DESIRED_CMAKE_VERSION} VERSION_LESS ${CMAKE_MINIMUM_REQUIRED_VERSION}) message(FATAL_ERROR "The desired version of CMake to be included in the package is " - "is below the minium required version of CMake to run") + "is below the minimum required version of CMake to run") endif() # pull down the desired copy of CMake so it can be included in the package From 881c51dc9c9ff3caa1f4b404c91e9cbaf74bd6ab Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 22:05:20 -0700 Subject: [PATCH 20/45] [cpack_installer] removed unnecessary explicit use of CMAKE_INSTALL_DEFAULT_COMPONENT_NAME --- cmake/Packaging.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index e2aa0f9348..e5799c8ff1 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -101,7 +101,6 @@ endif() install(FILES ${_cmake_package_dest} DESTINATION ./Tools/Redistributables/CMake - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) # IMPORTANT: required to be included AFTER setting all property overrides From 328ced0059f90f66d740d97e2f50721c9724995f Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 07:24:30 -0700 Subject: [PATCH 21/45] [cpack_installer] replaced missing get_target_property hack and fixed a typo --- cmake/Platform/Common/Install_common.cmake | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index e0301bb914..7e6917287f 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -27,11 +27,8 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) # De-alias target name ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) - # get the component ID. if the property isn't set for the target, fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME - get_target_property(install_componet ${TARGET_NAME} INSTALL_COMPONENT) - if("${install_componet}" STREQUAL "install_componet-NOTFOUND") - unset(install_componet) - endif() + # get the component ID. if the property isn't set for the target, it will auto fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME + get_property(install_component TARGET ${TARGET_NAME} PROPERTY INSTALL_COMPONENT) # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the @@ -47,7 +44,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) unset(current_public_headers) install(DIRECTORY ${include_directory} DESTINATION ${include_location}/${target_source_dir} - COMPONENT ${install_componet} + COMPONENT ${install_component} FILES_MATCHING PATTERN *.h PATTERN *.hpp @@ -74,13 +71,13 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) TARGETS ${TARGET_NAME} ARCHIVE DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ - COMPONENT ${install_componet} + COMPONENT ${install_component} LIBRARY DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} - COMPONENT ${install_componet} + COMPONENT ${install_component} RUNTIME DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} - COMPONENT ${install_componet} + COMPONENT ${install_component} ) # CMakeLists.txt file @@ -188,7 +185,7 @@ set_property(TARGET ${TARGET_NAME} file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" DESTINATION ${target_source_dir} - COMPONENT ${install_componet} + COMPONENT ${install_component} ) # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target @@ -247,11 +244,11 @@ function(ly_setup_subdirectory absolute_target_source_dir) ) # get the component ID. if the property isn't set for the directory, it will auto fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME - get_property(install_componet DIRECTORY ${absolute_target_source_dir} PROPERTY INSTALL_COMPONENT) + get_property(install_component DIRECTORY ${absolute_target_source_dir} PROPERTY INSTALL_COMPONENT) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt" DESTINATION ${target_source_dir} - COMPONENT ${install_componet} + COMPONENT ${install_component} ) endfunction() From 8214706ff9ab2c49cfafc7164bb6dbe0d296112c Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 08:24:01 -0700 Subject: [PATCH 22/45] [cpack_installer] reworked how packaging is enabled for windows --- cmake/Platform/Windows/Packaging_windows.cmake | 10 ++-------- scripts/build/Platform/Windows/build_config.json | 3 +-- scripts/build/Platform/Windows/build_windows.cmd | 8 -------- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 5210c24e7b..2fd281ad51 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -9,17 +9,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -set(LY_WIX_PATH "" CACHE PATH "Path to the WiX install path") - -if(LY_WIX_PATH) - file(TO_CMAKE_PATH ${LY_WIX_PATH} CPACK_WIX_ROOT) -elseif(DEFINED ENV{WIX}) - file(TO_CMAKE_PATH $ENV{WIX} CPACK_WIX_ROOT) -endif() +set(CPACK_WIX_ROOT "" CACHE PATH "Path to the WiX install path") if(CPACK_WIX_ROOT) if(NOT EXISTS ${CPACK_WIX_ROOT}) - message(FATAL_ERROR "Invalid path supplied for LY_WIX_PATH argument or WIX environment variable") + message(FATAL_ERROR "Invalid path supplied for CPACK_WIX_ROOT argument") endif() else() # early out as no path to WiX has been supplied effectively disabling support diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index b0d16f1fb6..fc4668de0a 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -314,8 +314,7 @@ "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", - "CMAKE_INCLUDE_WIX": "True", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DCPACK_WIX_ROOT=\"!WIX!\"", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index 799e6828b2..3e995e1905 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -38,14 +38,6 @@ IF NOT EXIST %TMP% ( REM Compute half the amount of processors so some jobs can run SET /a HALF_PROCESSORS = NUMBER_OF_PROCESSORS / 2 -IF "%CMAKE_INCLUDE_WIX%"=="True" ( - REM Explicitly enable wix via command line arg for forensic logging - SET CMAKE_OPTIONS=%CMAKE_OPTIONS% -DLY_WIX_PATH="%WIX%" -) ELSE ( - REM Disable implicit enabling of windows packing by clearing out the wix variable - SET WIX= -) - SET LAST_CONFIGURE_CMD_FILE=ci_last_configure_cmd.txt SET CONFIGURE_CMD=cmake %SOURCE_DIRECTORY% %CMAKE_OPTIONS% %EXTRA_CMAKE_OPTIONS% -DLY_3RDPARTY_PATH="%LY_3RDPARTY_PATH%" -DLY_PROJECTS=%CMAKE_LY_PROJECTS% IF NOT EXIST CMakeCache.txt ( From 5fbf587b9e34a88a7b26d8ccbde77f6ae9fa15a4 Mon Sep 17 00:00:00 2001 From: jckand-amzn Date: Thu, 3 Jun 2021 10:50:27 -0500 Subject: [PATCH 23/45] Updating File Menu actions in test_Menus_FileMenuOptions_Work. Temporarily marking test as xfail due to LYN-4208 --- .../EditorScripts/Menus_FileMenuOptions.py | 10 ++++----- .../Gem/PythonTests/editor/test_Menus.py | 21 ++++++++++--------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py index 3e174af2bd..734226a9d1 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py @@ -9,11 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ -""" -C24064528: The File menu options function normally -C16780778: The File menu options function normally-New view interaction Model enabled -""" - import os import sys @@ -54,7 +49,10 @@ class TestFileMenuOptions(EditorTestHelper): ("Save",), ("Save As",), ("Save Level Statistics",), - ("Project Settings", "Project Settings Tool"), + ("Edit Project Settings",), + ("Edit Platform Settings",), + ("New Project",), + ("Open Project",), ("Show Log File",), ("Resave All Slices",), ("Exit",), diff --git a/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py b/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py index c2da1343de..2b3fdcbdf3 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py +++ b/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py @@ -7,8 +7,6 @@ distribution (the "License"). All use of this software is governed by the Licens or, if provided, by the license below or the license accompanying this file. Do not remove or modify any license notices. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -C16780783: Base Edit Menu Options (New Viewport Interaction Model) """ import os @@ -17,6 +15,7 @@ import pytest # Bail on the test if ly_test_tools doesn't exist. pytest.importorskip('ly_test_tools') import ly_test_tools.environment.file_system as file_system +import ly_test_tools.environment.process_utils as process_utils import editor_python_test_tools.hydra_test_utils as hydra test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts") @@ -33,6 +32,7 @@ class TestMenus(object): def setup_teardown(self, request, workspace, project, level): def teardown(): file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) + process_utils.kill_processes_named("o3de", ignore_extensions=True) # Kill ProjectManager windows request.addfinalizer(teardown) @@ -80,8 +80,7 @@ class TestMenus(object): expected_lines, cfg_args=[level], run_python="--runpython", - auto_test_mode=True, - timeout=log_monitor_timeout, + timeout=log_monitor_timeout ) @pytest.mark.test_case_id("C16780807") @@ -107,13 +106,13 @@ class TestMenus(object): "Menus_ViewMenuOptions.py", expected_lines, cfg_args=[level], - auto_test_mode=True, run_python="--runpython", - timeout=log_monitor_timeout, + timeout=log_monitor_timeout ) @pytest.mark.test_case_id("C16780778") @pytest.mark.SUITE_sandbox + @pytest.mark.xfail # LYN-4208 def test_Menus_FileMenuOptions_Work(self, request, editor, level, launcher_platform): expected_lines = [ "New Level Action triggered", @@ -122,7 +121,10 @@ class TestMenus(object): "Save Action triggered", "Save As Action triggered", "Save Level Statistics Action triggered", - "Project Settings Tool Action triggered", + "Edit Project Settings Action triggered", + "Edit Platform Settings Action triggered", + "New Project Action triggered", + "Open Project Action triggered", "Show Log File Action triggered", "Resave All Slices Action triggered", "Exit Action triggered", @@ -135,7 +137,6 @@ class TestMenus(object): "Menus_FileMenuOptions.py", expected_lines, cfg_args=[level], - auto_test_mode=True, run_python="--runpython", - timeout=log_monitor_timeout, - ) \ No newline at end of file + timeout=log_monitor_timeout + ) From bcef8856ff2143fa137078525d98d47ddc6fe348 Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 10:51:13 -0700 Subject: [PATCH 24/45] [cpack_installer] minor wording fixes --- cmake/Packaging.cmake | 2 +- scripts/build/Platform/Windows/installer_windows.cmd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index e5799c8ff1..3e23511fa1 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -54,7 +54,7 @@ endif() if(${CPACK_DESIRED_CMAKE_VERSION} VERSION_LESS ${CMAKE_MINIMUM_REQUIRED_VERSION}) message(FATAL_ERROR "The desired version of CMake to be included in the package is " - "is below the minimum required version of CMake to run") + "below the minimum required version of CMake to run") endif() # pull down the desired copy of CMake so it can be included in the package diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index c71b091de9..a6ce15d59e 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -20,7 +20,7 @@ IF NOT EXIST %OUTPUT_DIRECTORY% ( ) PUSHD %OUTPUT_DIRECTORY% -REM Override the temporary directory used by wix to the EBS volume +REM Override the temporary directory used by wix to the workspace SET "WIX_TEMP=!WORKSPACE!/temp/wix" IF NOT EXIST "%WIX_TEMP%" ( MKDIR "%WIX_TEMP%" From dbeee91e7bc8d654e41fb420132036d94513a6b5 Mon Sep 17 00:00:00 2001 From: jckand-amzn Date: Thu, 3 Jun 2021 15:14:19 -0500 Subject: [PATCH 25/45] SPEC-7008: Setting up LargeWorlds main tests to be skipped in Debug builds --- .../dyn_veg/test_DynamicSliceInstanceSpawner.py | 6 ++++++ .../largeworlds/dyn_veg/test_EmptyInstanceSpawner.py | 6 ++++++ .../landscape_canvas/test_GraphComponentSync.py | 11 +++++++++++ 3 files changed, 23 insertions(+) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py index ead1e8779c..9235b302b8 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py @@ -16,6 +16,7 @@ import logging # Bail on the test if ly_test_tools doesn't exist. pytest.importorskip('ly_test_tools') import ly_test_tools.environment.file_system as file_system +import ly_test_tools._internal.pytest_plugin as internal_plugin import editor_python_test_tools.hydra_test_utils as hydra from ly_remote_console.remote_console_commands import RemoteConsole as RemoteConsole @@ -46,6 +47,11 @@ class TestDynamicSliceInstanceSpawner(object): @pytest.mark.parametrize("launcher_platform", ['windows_editor']) def test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(self, request, editor, level, workspace, project, launcher_platform): + + # Skip test if running against Debug build + if "debug" in internal_plugin.build_directory: + pytest.skip("Does not execute against debug builds.") + # Ensure temp level does not already exist file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py index ca71cd2137..83263c614a 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py @@ -16,6 +16,7 @@ import logging # Bail on the test if ly_test_tools doesn't exist. pytest.importorskip('ly_test_tools') import ly_test_tools.environment.file_system as file_system +import ly_test_tools._internal.pytest_plugin as internal_plugin import editor_python_test_tools.hydra_test_utils as hydra logger = logging.getLogger(__name__) @@ -40,6 +41,11 @@ class TestEmptyInstanceSpawner(object): @pytest.mark.SUITE_main @pytest.mark.dynveg_area def test_EmptyInstanceSpawner_EmptySpawnerWorks(self, request, editor, level, launcher_platform): + + # Skip test if running against Debug build + if "debug" in internal_plugin.build_directory: + pytest.skip("Does not execute against debug builds.") + cfg_args = [level] expected_lines = [ diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py index 855764fa6f..943d0cb985 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py @@ -23,6 +23,7 @@ import pytest # Bail on the test if ly_test_tools doesn't exist. pytest.importorskip('ly_test_tools') import ly_test_tools.environment.file_system as file_system +import ly_test_tools._internal.pytest_plugin as internal_plugin import editor_python_test_tools.hydra_test_utils as hydra test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts') @@ -46,6 +47,11 @@ class TestGraphComponentSync(object): @pytest.mark.BAT @pytest.mark.SUITE_main def test_LandscapeCanvas_SlotConnections_UpdateComponentReferences(self, request, editor, level, launcher_platform): + + # Skip test if running against Debug build + if "debug" in internal_plugin.build_directory: + pytest.skip("Does not execute against debug builds.") + cfg_args = [level] expected_lines = [ @@ -122,6 +128,11 @@ class TestGraphComponentSync(object): """ Verifies a Gradient Mixer can be setup in Landscape Canvas and all references are property set. """ + + # Skip test if running against Debug build + if "debug" in internal_plugin.build_directory: + pytest.skip("Does not execute against debug builds.") + cfg_args = [level] expected_lines = [ From d1f23aff62c4644ba7b3f9f8386c8014479f8b3b Mon Sep 17 00:00:00 2001 From: jckand-amzn Date: Thu, 3 Jun 2021 17:38:22 -0500 Subject: [PATCH 26/45] SPEC-7008: Excluding more main tests from Debug test runs --- .../Gem/PythonTests/editor/test_BasicEditorWorkflows.py | 5 +++++ .../largeworlds/landscape_canvas/test_GraphComponentSync.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/editor/test_BasicEditorWorkflows.py b/AutomatedTesting/Gem/PythonTests/editor/test_BasicEditorWorkflows.py index b045b364a3..f65401f007 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/test_BasicEditorWorkflows.py +++ b/AutomatedTesting/Gem/PythonTests/editor/test_BasicEditorWorkflows.py @@ -15,6 +15,7 @@ import pytest # Bail on the test if ly_test_tools doesn't exist. pytest.importorskip('ly_test_tools') import ly_test_tools.environment.file_system as file_system +import ly_test_tools._internal.pytest_plugin as internal_plugin import editor_python_test_tools.hydra_test_utils as hydra test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts") @@ -40,6 +41,10 @@ class TestBasicEditorWorkflows(object): @pytest.mark.SUITE_main def test_BasicEditorWorkflows_LevelEntityComponentCRUD(self, request, editor, level, launcher_platform): + # Skip test if running against Debug build + if "debug" in internal_plugin.build_directory: + pytest.skip("Does not execute against debug builds.") + expected_lines = [ "Create and load new level: True", "New entity creation: True", diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py index 943d0cb985..e7dc046480 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py @@ -132,7 +132,7 @@ class TestGraphComponentSync(object): # Skip test if running against Debug build if "debug" in internal_plugin.build_directory: pytest.skip("Does not execute against debug builds.") - + cfg_args = [level] expected_lines = [ From 85e6d06c2c203b7883053f97e8827689e10a5ae2 Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 16:09:10 -0700 Subject: [PATCH 27/45] [default_3rdparty] add 3rd party to engine registration + specific path registration fixes --- .../ProjectManager/Source/PythonBindings.cpp | 22 +++--------- scripts/o3de/o3de/manifest.py | 8 +++++ scripts/o3de/o3de/register.py | 35 +++++++++++++++---- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 7062d886da..e2c84b2b5f 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -383,7 +383,7 @@ namespace O3DE::ProjectManager engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]); engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]); engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]); - engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"third_party_path",""); + engineInfo.m_thirdPartyPath = Py_To_String(o3deData["default_third_party_folder"]); } auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); @@ -420,6 +420,7 @@ namespace O3DE::ProjectManager pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString(); pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString(); pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString(); + pybind11::str defaultThridPartyFolder = engineInfo.m_thirdPartyPath.toStdString(); auto registrationResult = m_register.attr("register")( enginePath, // engine_path @@ -432,28 +433,15 @@ namespace O3DE::ProjectManager pybind11::none(), // default_engines_folder defaultProjectsFolder, defaultGemsFolder, - defaultTemplatesFolder + defaultTemplatesFolder, + pybind11::none(), // default_restricted_folder + defaultThridPartyFolder ); if (registrationResult.cast() != 0) { result = false; } - - auto manifest = m_manifest.attr("load_o3de_manifest")(); - if (pybind11::isinstance(manifest)) - { - try - { - manifest["third_party_path"] = engineInfo.m_thirdPartyPath.toStdString(); - m_manifest.attr("save_o3de_manifest")(manifest); - } - catch ([[maybe_unused]] const std::exception& e) - { - AZ_Warning("PythonBindings", false, "Failed to set third party path."); - } - } - }); return result; diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index edcd44c525..3fa21721c2 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -97,6 +97,12 @@ def get_o3de_logs_folder() -> pathlib.Path: return logs_folder +def get_o3de_third_party_folder() -> pathlib.Path: + third_party_folder = get_o3de_folder() / '3rdParty' + third_party_folder.mkdir(parents=True, exist_ok=True) + return third_party_folder + + # o3de manifest file methods def get_o3de_manifest() -> pathlib.Path: manifest_path = get_o3de_folder() / 'o3de_manifest.json' @@ -113,6 +119,7 @@ def get_o3de_manifest() -> pathlib.Path: default_gems_folder = get_o3de_gems_folder() default_templates_folder = get_o3de_templates_folder() default_restricted_folder = get_o3de_restricted_folder() + default_third_party_folder = get_o3de_third_party_folder() default_projects_restricted_folder = default_projects_folder / 'Restricted' default_projects_restricted_folder.mkdir(parents=True, exist_ok=True) @@ -129,6 +136,7 @@ def get_o3de_manifest() -> pathlib.Path: json_data.update({'default_gems_folder': default_gems_folder.as_posix()}) json_data.update({'default_templates_folder': default_templates_folder.as_posix()}) json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()}) + json_data.update({'default_third_party_folder': default_third_party_folder.as_posix()}) json_data.update({'projects': []}) json_data.update({'external_subdirectories': []}) diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 68575488dc..2e37f04acf 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -486,7 +486,7 @@ def register_default_engines_folder(json_data: dict, remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_engines_folder() if remove else default_engines_folder, - 'default_engines_folder', remove) + 'default_engines_folder') def register_default_projects_folder(json_data: dict, @@ -494,7 +494,7 @@ def register_default_projects_folder(json_data: dict, remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_projects_folder() if remove else default_projects_folder, - 'default_projects_folder', remove) + 'default_projects_folder') def register_default_gems_folder(json_data: dict, @@ -502,7 +502,7 @@ def register_default_gems_folder(json_data: dict, remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_gems_folder() if remove else default_gems_folder, - 'default_gems_folder', remove) + 'default_gems_folder') def register_default_templates_folder(json_data: dict, @@ -510,16 +510,22 @@ def register_default_templates_folder(json_data: dict, remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_templates_folder() if remove else default_templates_folder, - 'default_templates_folder', remove) + 'default_templates_folder') def register_default_restricted_folder(json_data: dict, default_restricted_folder: str or pathlib.Path, - reset_to_default: bool = False) -> int: + remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_restricted_folder() if remove else default_restricted_folder, - 'default_restricted_folder', remove) + 'default_restricted_folder') +def register_default_third_party_folder(json_data: dict, + default_third_party_folder: str or pathlib.Path, + remove: bool = False) -> int: + return register_default_o3de_object_folder(json_data, + manifest.get_o3de_third_party_folder() if remove else default_third_party_folder, + 'default_third_party_folder') def register(engine_path: str or pathlib.Path = None, project_path: str or pathlib.Path = None, @@ -533,6 +539,7 @@ def register(engine_path: str or pathlib.Path = None, default_gems_folder: str or pathlib.Path = None, default_templates_folder: str or pathlib.Path = None, default_restricted_folder: str or pathlib.Path = None, + default_third_party_folder: str or pathlib.Path = None, external_subdir_engine_path: pathlib.Path = None, external_subdir_project_path: pathlib.Path = None, remove: bool = False, @@ -553,6 +560,7 @@ def register(engine_path: str or pathlib.Path = None, :param default_gems_folder: default gems folder :param default_templates_folder: default templates folder :param default_restricted_folder: default restricted code folder + :param default_third_party_folder: default 3rd party cache folder :param external_subdir_engine_path: Path to the engine to use when registering an external subdirectory. The registration occurs in the engine.json file in this case :param external_subdir_engine_path: Path to the project to use when registering an external subdirectory. @@ -620,6 +628,9 @@ def register(engine_path: str or pathlib.Path = None, elif isinstance(default_restricted_folder, str) or isinstance(default_restricted_folder, pathlib.PurePath): result = register_default_restricted_folder(json_data, default_restricted_folder, remove) + elif isinstance(default_third_party_folder, str) or isinstance(default_third_party_folder, pathlib.PurePath): + result = register_default_third_party_folder(json_data, default_third_party_folder, remove) + # engine is done LAST # Now that everything that could have an engine context is done, if the engine is supplied that means this is # registering the engine itself @@ -712,6 +723,15 @@ def remove_invalid_o3de_objects() -> None: f" Set default {default_restricted_folder}") register(default_restricted_folder=default_restricted_folder.as_posix()) + default_third_party_folder = pathlib.Path(json_data['default_third_party_folder']).resolve() + if not default_third_party_folder.is_dir(): + default_third_party_folder = manifest.get_o3de_folder() / '3rdParty' + default_third_party_folder.mkdir(parents=True, exist_ok=True) + logger.warn( + f"Default 3rd Party folder {default_third_party_folder} is invalid." + f" Set default {default_third_party_folder}") + register(default_third_party_folder=default_third_party_folder.as_posix()) + def _run_register(args: argparse) -> int: if args.override_home_folder: @@ -751,6 +771,7 @@ def _run_register(args: argparse) -> int: default_gems_folder=args.default_gems_folder, default_templates_folder=args.default_templates_folder, default_restricted_folder=args.default_restricted_folder, + default_third_party_folder=args.default_third_party_folder, external_subdir_engine_path=args.external_subdirectory_engine_path, external_subdir_project_path=args.external_subdirectory_project_path, remove=args.remove, @@ -804,6 +825,8 @@ def add_parser_args(parser): help='The default templates folder to register/remove.') group.add_argument('-drf', '--default-restricted-folder', type=str, required=False, help='The default restricted folder to register/remove.') + group.add_argument('-dtpf', '--default-third-party-folder', type=str, required=False, + help='The default 3rd Party folder to register/remove.') group.add_argument('-u', '--update', action='store_true', required=False, default=False, help='Refresh the repo cache.') From 816d05ef2d85843c86fd47265cc8cf1a3b55c3c5 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 3 Jun 2021 18:16:22 -0500 Subject: [PATCH 28/45] Updating manifest.py template query functions (#1113) * Updating manifest.py template query functions The get_project_templates, get_gem_templates and get_generic_templates methods have been renamed to indicate that the methods return the templates that can be used in a create-project, create-gem and create-from-template command of the engine_template.py Updated the print_registration.py script to support outputing project specific gems and templates. Add a unit test script for the manifest.py script. Added unit test to validate the new functions: `get_templates_for_project_creation` `get_templates_for_gem_creation` `get_templates_for_generic_creation` * Implementing the project print registration methods Added implementations of the project print registration methods and tested them locally Removed implementations of the download print registration methods, since they have not went through app-sec review. * Renaming get_restricted_data to get_restricted_json_data Fixed the get_registered method in manifest.py when looking up projects * Updated the print_manifest_json_data calls to return the result --- .../ProjectManager/Source/PythonBindings.cpp | 215 ++++---- scripts/o3de/o3de/manifest.py | 97 ++-- scripts/o3de/o3de/print_registration.py | 496 +++++++++--------- scripts/o3de/tests/CMakeLists.txt | 7 + scripts/o3de/tests/unit_test_manifest.py | 111 ++++ scripts/o3de/tests/unit_test_utils.py | 2 +- 6 files changed, 542 insertions(+), 386 deletions(-) create mode 100644 scripts/o3de/tests/unit_test_manifest.py diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 7062d886da..18b29c496f 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -294,7 +294,8 @@ namespace O3DE::ProjectManager RegisterThisEngine(); return result == 0 && !PyErr_Occurred(); - } catch ([[maybe_unused]] const std::exception& e) + } + catch ([[maybe_unused]] const std::exception& e) { AZ_Warning("ProjectManagerWindow", false, "Py_Initialize() failed with %s", e.what()); return false; @@ -320,25 +321,25 @@ namespace O3DE::ProjectManager bool registrationResult = true; // already registered is considered successful bool pythonResult = ExecuteWithLock( [&] + { + // check current engine path against all other registered engines + // to see if we are already registered + auto allEngines = m_manifest.attr("get_engines")(); + if (pybind11::isinstance(allEngines)) { - // check current engine path against all other registered engines - // to see if we are already registered - auto allEngines = m_manifest.attr("get_engines")(); - if (pybind11::isinstance(allEngines)) + for (auto engine : allEngines) { - for (auto engine : allEngines) + AZ::IO::FixedMaxPath enginePath(Py_To_String(engine["path"])); + if (enginePath.Compare(m_enginePath) == 0) { - AZ::IO::FixedMaxPath enginePath(Py_To_String(engine["path"])); - if (enginePath.Compare(m_enginePath) == 0) - { - return; - } + return; } } + } - auto result = m_register.attr("register")(m_enginePath.c_str()); - registrationResult = (result.cast() == 0); - }); + auto result = m_register.attr("register")(m_enginePath.c_str()); + registrationResult = (result.cast() == 0); + }); bool finalResult = (registrationResult && pythonResult); AZ_Assert(finalResult, "Registration of this engine failed!"); @@ -378,12 +379,12 @@ namespace O3DE::ProjectManager auto o3deData = m_manifest.attr("load_o3de_manifest")(); if (pybind11::isinstance(o3deData)) { - engineInfo.m_path = Py_To_String(enginePath); - engineInfo.m_defaultGemsFolder = Py_To_String(o3deData["default_gems_folder"]); - engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]); + engineInfo.m_path = Py_To_String(enginePath); + engineInfo.m_defaultGemsFolder = Py_To_String(o3deData["default_gems_folder"]); + engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]); engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]); - engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]); - engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"third_party_path",""); + engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]); + engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData, "third_party_path", ""); } auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); @@ -391,8 +392,8 @@ namespace O3DE::ProjectManager { try { - engineInfo.m_version = Py_To_String_Optional(engineData,"O3DEVersion","0.0.0.0"); - engineInfo.m_name = Py_To_String_Optional(engineData,"engine_name","O3DE"); + engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0"); + engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE"); } catch ([[maybe_unused]] const std::exception& e) { @@ -416,19 +417,19 @@ namespace O3DE::ProjectManager bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo) { bool result = ExecuteWithLock([&] { - pybind11::str enginePath = engineInfo.m_path.toStdString(); - pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString(); - pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString(); + pybind11::str enginePath = engineInfo.m_path.toStdString(); + pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString(); + pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString(); pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString(); auto registrationResult = m_register.attr("register")( - enginePath, // engine_path - pybind11::none(), // project_path + enginePath, // engine_path + pybind11::none(), // project_path pybind11::none(), // gem_path - pybind11::none(), // external_subdir_path - pybind11::none(), // template_path - pybind11::none(), // restricted_path - pybind11::none(), // repo_uri + pybind11::none(), // external_subdir_path + pybind11::none(), // template_path + pybind11::none(), // restricted_path + pybind11::none(), // repo_uri pybind11::none(), // default_engines_folder defaultProjectsFolder, defaultGemsFolder, @@ -477,12 +478,12 @@ namespace O3DE::ProjectManager QVector gems; auto result = ExecuteWithLockErrorHandling([&] + { + for (auto path : m_manifest.attr("get_engine_gems")()) { - for (auto path : m_manifest.attr("get_engine_gems")()) - { - gems.push_back(GemInfoFromPath(path)); - } - }); + gems.push_back(GemInfoFromPath(path)); + } + }); if (!result.IsSuccess()) { return AZ::Failure(result.GetError().c_str()); @@ -497,13 +498,13 @@ namespace O3DE::ProjectManager QVector gems; auto result = ExecuteWithLockErrorHandling([&] + { + pybind11::str pyProjectPath = projectPath.toStdString(); + for (auto path : m_manifest.attr("get_all_gems")(pyProjectPath)) { - pybind11::str pyProjectPath = projectPath.toStdString(); - for (auto path : m_manifest.attr("get_all_gems")(pyProjectPath)) - { - gems.push_back(GemInfoFromPath(path)); - } - }); + gems.push_back(GemInfoFromPath(path)); + } + }); if (!result.IsSuccess()) { return AZ::Failure(result.GetError().c_str()); @@ -518,12 +519,12 @@ namespace O3DE::ProjectManager // Retrieve the path to the cmake file that lists the enabled gems. pybind11::str enabledGemsFilename; auto result = ExecuteWithLockErrorHandling([&] - { - const pybind11::str pyProjectPath = projectPath.toStdString(); - enabledGemsFilename = m_cmake.attr("get_enabled_gem_cmake_file")( - pybind11::none(), // project_name - pyProjectPath); // project_path - }); + { + const pybind11::str pyProjectPath = projectPath.toStdString(); + enabledGemsFilename = m_cmake.attr("get_enabled_gem_cmake_file")( + pybind11::none(), // project_name + pyProjectPath); // project_path + }); if (!result.IsSuccess()) { return AZ::Failure(result.GetError().c_str()); @@ -532,13 +533,13 @@ namespace O3DE::ProjectManager // Retrieve the actual list of names from the cmake file. QVector gemNames; result = ExecuteWithLockErrorHandling([&] + { + const auto pyGemNames = m_cmake.attr("get_enabled_gems")(enabledGemsFilename); + for (auto gemName : pyGemNames) { - const auto pyGemNames = m_cmake.attr("get_enabled_gems")(enabledGemsFilename); - for (auto gemName : pyGemNames) - { - gemNames.push_back(Py_To_String(gemName)); - } - }); + gemNames.push_back(Py_To_String(gemName)); + } + }); if (!result.IsSuccess()) { return AZ::Failure(result.GetError().c_str()); @@ -552,13 +553,13 @@ namespace O3DE::ProjectManager bool registrationResult = false; bool result = ExecuteWithLock( [&] - { - pybind11::str projectPath = path.toStdString(); - auto pythonRegistrationResult = m_register.attr("register")(pybind11::none(), projectPath); + { + pybind11::str projectPath = path.toStdString(); + auto pythonRegistrationResult = m_register.attr("register")(pybind11::none(), projectPath); - // Returns an exit code so boolify it then invert result - registrationResult = !pythonRegistrationResult.cast(); - }); + // Returns an exit code so boolify it then invert result + registrationResult = !pythonRegistrationResult.cast(); + }); return result && registrationResult; } @@ -568,30 +569,30 @@ namespace O3DE::ProjectManager bool registrationResult = false; bool result = ExecuteWithLock( [&] - { - pybind11::str projectPath = path.toStdString(); - auto pythonRegistrationResult = m_register.attr("register")( - pybind11::none(), // engine_path - projectPath, // project_path - pybind11::none(), // gem_path - pybind11::none(), // external_subdir_path - pybind11::none(), // template_path - pybind11::none(), // restricted_path - pybind11::none(), // repo_uri - pybind11::none(), // default_engines_folder - pybind11::none(), // default_projects_folder - pybind11::none(), // default_gems_folder - pybind11::none(), // default_templates_folder - pybind11::none(), // default_restricted_folder - pybind11::none(), // external_subdir_engine_path - pybind11::none(), // external_subdir_project_path - true, // remove - false // force + { + pybind11::str projectPath = path.toStdString(); + auto pythonRegistrationResult = m_register.attr("register")( + pybind11::none(), // engine_path + projectPath, // project_path + pybind11::none(), // gem_path + pybind11::none(), // external_subdir_path + pybind11::none(), // template_path + pybind11::none(), // restricted_path + pybind11::none(), // repo_uri + pybind11::none(), // default_engines_folder + pybind11::none(), // default_projects_folder + pybind11::none(), // default_gems_folder + pybind11::none(), // default_templates_folder + pybind11::none(), // default_restricted_folder + pybind11::none(), // external_subdir_engine_path + pybind11::none(), // external_subdir_project_path + true, // remove + false // force ); - - // Returns an exit code so boolify it then invert result - registrationResult = !pythonRegistrationResult.cast(); - }); + + // Returns an exit code so boolify it then invert result + registrationResult = !pythonRegistrationResult.cast(); + }); return result && registrationResult; } @@ -649,12 +650,12 @@ namespace O3DE::ProjectManager try { // required - gemInfo.m_name = Py_To_String(data["gem_name"]); + gemInfo.m_name = Py_To_String(data["gem_name"]); // optional gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name); - gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); - gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); + gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); + gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); if (data.contains("Tags")) { @@ -685,7 +686,7 @@ namespace O3DE::ProjectManager try { projectInfo.m_projectName = Py_To_String(projectData["project_name"]); - projectInfo.m_displayName = Py_To_String_Optional(projectData,"display_name", projectInfo.m_projectName); + projectInfo.m_displayName = Py_To_String_Optional(projectData, "display_name", projectInfo.m_projectName); } catch ([[maybe_unused]] const std::exception& e) { @@ -727,33 +728,33 @@ namespace O3DE::ProjectManager AZ::Outcome PythonBindings::AddGemToProject(const QString& gemPath, const QString& projectPath) { return ExecuteWithLockErrorHandling([&] - { - pybind11::str pyGemPath = gemPath.toStdString(); - pybind11::str pyProjectPath = projectPath.toStdString(); + { + pybind11::str pyGemPath = gemPath.toStdString(); + pybind11::str pyProjectPath = projectPath.toStdString(); - m_enableGemProject.attr("enable_gem_in_project")( - pybind11::none(), // gem name not needed as path is provided - pyGemPath, - pybind11::none(), // project name not needed as path is provided - pyProjectPath + m_enableGemProject.attr("enable_gem_in_project")( + pybind11::none(), // gem name not needed as path is provided + pyGemPath, + pybind11::none(), // project name not needed as path is provided + pyProjectPath ); - }); + }); } AZ::Outcome PythonBindings::RemoveGemFromProject(const QString& gemPath, const QString& projectPath) { return ExecuteWithLockErrorHandling([&] - { - pybind11::str pyGemPath = gemPath.toStdString(); - pybind11::str pyProjectPath = projectPath.toStdString(); + { + pybind11::str pyGemPath = gemPath.toStdString(); + pybind11::str pyProjectPath = projectPath.toStdString(); - m_disableGemProject.attr("disable_gem_in_project")( - pybind11::none(), // gem name not needed as path is provided - pyGemPath, - pybind11::none(), // project name not needed as path is provided - pyProjectPath + m_disableGemProject.attr("disable_gem_in_project")( + pybind11::none(), // gem name not needed as path is provided + pyGemPath, + pybind11::none(), // project name not needed as path is provided + pyProjectPath ); - }); + }); } bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo) @@ -773,8 +774,8 @@ namespace O3DE::ProjectManager { // required templateInfo.m_displayName = Py_To_String(data["display_name"]); - templateInfo.m_name = Py_To_String(data["template_name"]); - templateInfo.m_summary = Py_To_String(data["summary"]); + templateInfo.m_name = Py_To_String(data["template_name"]); + templateInfo.m_summary = Py_To_String(data["summary"]); // optional if (data.contains("canonical_tags")) @@ -806,7 +807,7 @@ namespace O3DE::ProjectManager QVector templates; bool result = ExecuteWithLock([&] { - for (auto path : m_manifest.attr("get_project_templates")()) + for (auto path : m_manifest.attr("get_templates_for_project_creation")()) { templates.push_back(ProjectTemplateInfoFromPath(path)); } diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index edcd44c525..bcb331d9f4 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -302,64 +302,95 @@ def get_project_external_subdirectories(project_path: pathlib.Path) -> list: project_object['external_subdirectories'])) if 'external_subdirectories' in project_object else [] +def get_project_templates(project_path: pathlib.Path) -> list: + project_object = get_project_json_data(project_path=project_path) + return list(map(lambda rel_path: (pathlib.Path(project_path) / rel_path).as_posix(), + project_object['templates'])) + + +def get_project_restricted(project_path: pathlib.Path) -> list: + project_object = get_project_json_data(project_path=project_path) + return list(map(lambda rel_path: (pathlib.Path(project_path) / rel_path).as_posix(), + project_object['restricted'])) if 'restricted' in project_object else [] + + # Combined manifest queries def get_all_projects() -> list: - projects_data = set(get_projects()) - projects_data.update(get_engine_projects()) - return list(projects_data) + projects_data = get_projects() + projects_data.extend(get_engine_projects()) + # Remove duplicates from the list + return list(dict.fromkeys(projects_data)) def get_all_gems(project_path: pathlib.Path = None) -> list: - gems_data = set(get_gems()) - gems_data.update(get_engine_gems()) + gems_data = get_gems() + gems_data.extend(get_engine_gems()) if project_path: - gems_data.update(get_project_gems(project_path)) - return list(gems_data) + gems_data.extend(get_project_gems(project_path)) + return list(dict.fromkeys(gems_data)) def get_all_external_subdirectories(project_path: pathlib.Path = None) -> list: - external_subdirectories_data = set(get_external_subdirectories()) - external_subdirectories_data.update(get_engine_external_subdirectories()) + external_subdirectories_data = get_external_subdirectories() + external_subdirectories_data.extend(get_engine_external_subdirectories()) if project_path: - external_subdirectories_data.update(get_project_external_subdirectories(project_path)) - return list(templates_data) + external_subdirectories_data.extend(get_project_external_subdirectories(project_path)) + return list(dict.fromkeys(external_subdirectories_data)) -def get_all_templates() -> list: - templates_data = set(get_templates()) - templates_data.update(get_engine_templates()) - return list(templates_data) +def get_all_templates(project_path: pathlib.Path = None) -> list: + templates_data = get_templates() + templates_data.extend(get_engine_templates()) + if project_path: + templates_data.extend(get_project_templates(project_path)) + return list(dict.fromkeys(templates_data)) def get_all_restricted() -> list: - restricted_data = set(get_restricted()) - restricted_data.update(get_engine_restricted()) - return list(gems_data) + restricted_data = get_restricted() + restricted_data.extend(get_engine_restricted()) + if project_path: + restricted_data.extend(get_project_restricted(project_path)) + return list(dict.fromkeys(restricted_data)) # Template functions -def get_project_templates(): # temporary until we have a better way to do this... maybe template_type element +def get_templates_for_project_creation(): project_templates = [] - for template in get_all_templates(): - if 'Project' in template: - project_templates.append(template) + for template_path in get_all_templates(): + template_path = pathlib.Path(template_path) + template_json_path = pathlib.Path(template_path) / 'template.json' + if not validation.valid_o3de_template_json(template_json_path): + continue + + project_json_path = template_path / 'Template' / 'project.json' + if validation.valid_o3de_project_json(project_json_path): + project_templates.append(template_path) return project_templates -def get_gem_templates(): # temporary until we have a better way to do this... maybe template_type element +def get_templates_for_gem_creation(): gem_templates = [] - for template in get_all_templates(): - if 'Gem' in template: - gem_templates.append(template) + for template_path in get_all_templates(): + template_path = pathlib.Path(template_path) + template_json_path = pathlib.Path(template_path) / 'template.json' + if not validation.valid_o3de_template_json(template_json_path): + continue + + gem_json_path = template_path / 'Template' / 'gem.json' + if validation.valid_o3de_gem_json(gem_json_path): + gem_templates.append(template_path) return gem_templates -def get_generic_templates(): # temporary until we have a better way to do this... maybe template_type element - generic_templates = [] - for template in get_all_templates(): - if 'Project' not in template and 'Gem' not in template: - generic_templates.append(template) - return generic_templates +def get_templates_for_generic_creation(): # temporary until we have a better way to do this... maybe template_type element + def filter_project_and_gem_templates_out(template_path, + templates_for_project_creation = get_templates_for_project_creation(), + templates_for_gem_creation = get_templates_for_gem_creation()): + template_path = pathlib.Path(template_path) + return template_path not in templates_for_project_creation and template_path not in templates_for_gem_creation + + return list(filter(filter_project_and_gem_templates_out, get_all_templates())) def get_all_restricted() -> list: @@ -515,7 +546,7 @@ def get_template_json_data(template_name: str = None, return None -def get_restricted_data(restricted_name: str = None, +def get_restricted_json_data(restricted_name: str = None, restricted_path: str or pathlib.Path = None) -> dict or None: if not restricted_name and not restricted_path: logger.error('Must specify either a Restricted name or Restricted Path.') diff --git a/scripts/o3de/o3de/print_registration.py b/scripts/o3de/o3de/print_registration.py index 292f2224bc..e5c7a1afc0 100644 --- a/scripts/o3de/o3de/print_registration.py +++ b/scripts/o3de/o3de/print_registration.py @@ -13,6 +13,7 @@ import argparse import json import hashlib import logging +import pathlib import sys import urllib.parse @@ -21,219 +22,251 @@ from o3de import manifest, validation logger = logging.getLogger() logging.basicConfig() -def print_this_engine(verbose: int) -> None: + +def get_project_path(project_path: pathlib.Path, project_name: str) -> pathlib.Path: + if not project_name and not project_path: + logger.error(f'Must either specify a Project path or Project Name.') + return None + + if not project_path: + project_path = manifest.get_registered(project_name=project_name) + if not project_path: + logger.error(f'Unable to locate project path from the registered manifest json files:' + f' {str(pathlib.Path("~/.o3de/o3de_manifest.json").expanduser())}, engine.json') + return None + + if not project_path.is_dir(): + logger.error(f'Project path {project_path} is not a folder.') + return None + + return project_path + + +def print_this_engine(verbose: int) -> int: engine_data = manifest.get_this_engine() print(json.dumps(engine_data, indent=4)) + result = True if verbose > 0: - print_engines_data(engine_data) + result = print_manifest_json_data(engine_data, 'engine.json', 'This Engine', + manifest.get_engine_json_data, 'engine_path') + return 0 if result else 1 def print_engines(verbose: int) -> None: engines_data = manifest.get_engines() print(json.dumps(engines_data, indent=4)) + if verbose > 0: - print_engines_data(engines_data) + return print_manifest_json_data(engines_data, 'engine.json', 'Engines', + manifest.get_engine_json_data, 'engine_path') + return 0 -def print_projects(verbose: int) -> None: +def print_projects(verbose: int) -> int: projects_data = manifest.get_projects() print(json.dumps(projects_data, indent=4)) + if verbose > 0: - print_projects_data(projects_data) + return print_manifest_json_data(projects_data, 'project.json', 'Projects', + manifest.get_project_json_data, 'project_path') + return 0 -def print_gems(verbose: int) -> None: +def print_gems(verbose: int) -> int: gems_data = manifest.get_gems() print(json.dumps(gems_data, indent=4)) + if verbose > 0: - print_gems_data(gems_data) + return print_manifest_json_data(gems_data, 'gem.json', 'Gems', + manifest.get_gem_json_data, 'gem_path') + return 0 -def print_templates(verbose: int) -> None: +def print_templates(verbose: int) -> int: templates_data = manifest.get_templates() print(json.dumps(templates_data, indent=4)) + if verbose > 0: - print_templates_data(templates_data) + return print_manifest_json_data(templates_data, 'template.json', 'Templates', + manifest.get_template_json_data, 'template_path') + return 0 -def print_restricted(verbose: int) -> None: +def print_restricted(verbose: int) -> int: restricted_data = manifest.get_restricted() print(json.dumps(restricted_data, indent=4)) - if verbose > 0: - print_restricted_data(restricted_data) -def print_engine_projects(verbose: int) -> None: + if verbose > 0: + return print_manifest_json_data(restricted_data, 'restricted.json', 'Restricted', + manifest.get_restricted_json_data, 'restricted_path') + return 0 + + +# Engine output methods +def print_engine_projects(verbose: int) -> int: engine_projects_data = manifest.get_engine_projects() print(json.dumps(engine_projects_data, indent=4)) + if verbose > 0: - print_projects_data(engine_projects_data) + return print_manifest_json_data(engine_projects_data, 'project.json', 'Projects', + manifest.get_project_json_data, 'project_path') + return 0 -def print_engine_gems(verbose: int) -> None: +def print_engine_gems(verbose: int) -> int: engine_gems_data = manifest.get_engine_gems() print(json.dumps(engine_gems_data, indent=4)) + if verbose > 0: - print_gems_data(engine_gems_data) + return print_manifest_json_data(engine_gems_data, 'gem.json', 'Gems', + manifest.get_gem_json_data, 'gem_path') + return 0 -def print_engine_templates(verbose: int) -> None: +def print_engine_templates(verbose: int) -> int: engine_templates_data = manifest.get_engine_templates() print(json.dumps(engine_templates_data, indent=4)) + if verbose > 0: - print_templates_data(engine_templates_data) + return print_manifest_json_data(engine_templates_data, 'template.json', 'Templates', + manifest.get_template_json_data, 'template_path') + return 0 -def print_engine_restricted(verbose: int) -> None: +def print_engine_restricted(verbose: int) -> int: engine_restricted_data = manifest.get_engine_restricted() print(json.dumps(engine_restricted_data, indent=4)) + if verbose > 0: - print_restricted_data(engine_restricted_data) + return print_manifest_json_data(engine_restricted_data, 'restricted.json', 'Restricted', + manifest.get_restricted_json_data, 'restricted_path') + return 0 -def print_engine_external_subdirectories(verbose: int) -> None: +def print_engine_external_subdirectories() -> int: external_subdirs_data = manifest.get_engine_external_subdirectories() print(json.dumps(external_subdirs_data, indent=4)) + return 0 -def print_all_projects(verbose: int) -> None: +# Project output methods +def print_project_gems(verbose: int, project_path: pathlib.Path, project_name: str) -> int: + project_path = get_project_path(project_path, project_name) + if not project_path: + return 1 + + project_gems_data = manifest.get_project_gems(project_path) + print(json.dumps(project_gems_data, indent=4)) + + if verbose > 0: + return print_manifest_json_data(project_gems_data, 'gem.json', 'Gems', + manifest.get_gem_json_data, 'gem_path') + return 0 + + +def print_project_external_subdirectories(project_path: pathlib.Path, project_name: str) -> int: + project_path = get_project_path(project_path, project_name) + if not project_path: + return 1 + + external_subdirs_data = manifest.get_project_external_subdirectories(project_path) + print(json.dumps(external_subdirs_data, indent=4)) + return 0 + + +def print_project_templates(verbose: int, project_path: pathlib.Path, project_name: str) -> int: + project_path = get_project_path(project_path, project_name) + if not project_path: + return 1 + + project_templates_data = manifest.get_project_templates(project_path) + print(json.dumps(project_templates_data, indent=4)) + if verbose > 0: + return print_manifest_json_data(project_templates_data, 'template.json', 'Templates', + manifest.get_template_json_data, 'template_path') + return 0 + + +def print_project_restricted(verbose: int, project_path: pathlib.Path, project_name: str) -> int: + project_path = get_project_path(project_path, project_name) + if not project_path: + return 1 + + project_restricted_data = manifest.get_project_restricted(project_path) + print(json.dumps(project_restricted_data, indent=4)) + if verbose > 0: + return print_manifest_json_data(project_restricted_data, 'restricted.json', 'Restricted', + manifest.get_restricted_json_data, 'restricted_path') + return 0 + + +def print_all_projects(verbose: int) -> int: all_projects_data = manifest.get_all_projects() print(json.dumps(all_projects_data, indent=4)) + if verbose > 0: - print_projects_data(all_projects_data) + return print_manifest_json_data(all_projects_data, 'project.json', 'Projects', + manifest.get_project_json_data, 'project_path') + return 0 -def print_all_gems(verbose: int) -> None: +def print_all_gems(verbose: int) -> int: all_gems_data = manifest.get_all_gems() print(json.dumps(all_gems_data, indent=4)) + if verbose > 0: - print_gems_data(all_gems_data) + return print_manifest_json_data(all_gems_data, 'gem.json', 'Gems', + manifest.get_gem_json_data, 'gem_path') + return 0 -def print_all_templates(verbose: int) -> None: +def print_all_external_subdirectories() -> int: + all_external_subdirectories_data = manifest.get_all_external_subdirectories() + print(json.dumps(all_external_subdirectories_data, indent=4)) + return 0 + +def print_all_templates(verbose: int) -> int: all_templates_data = manifest.get_all_templates() print(json.dumps(all_templates_data, indent=4)) + if verbose > 0: - print_templates_data(all_templates_data) + return print_manifest_json_data(all_templates_data, 'template.json', 'Templates', + manifest.get_template_json_data, 'template_path') + return 0 -def print_all_restricted(verbose: int) -> None: +def print_all_restricted(verbose: int) -> int: all_restricted_data = manifest.get_all_restricted() print(json.dumps(all_restricted_data, indent=4)) + if verbose > 0: - print_restricted_data(all_restricted_data) + return print_manifest_json_data(all_restricted_data, 'restricted.json', 'Restricted', + manifest.get_restricted_json_data, 'restricted_path') + return 0 -def print_engines_data(engines_data: dict) -> None: +def print_manifest_json_data(uri_json_data: dict, json_filename: str, + print_prefix: str, get_json_func: callable, get_json_data_kw: str) -> int: print('\n') - print("Engines================================================") - for engine_object in engines_data: + print(f"{print_prefix}================================================") + for manifest_uri in uri_json_data: # if it's not local it should be in the cache - engine_uri = engine_object['path'] - parsed_uri = urllib.parse.urlparse(engine_uri) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - repo_sha256 = hashlib.sha256(engine_uri.encode()) + parsed_uri = urllib.parse.urlparse(manifest_uri) + if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: + repo_sha256 = hashlib.sha256(manifest_uri.encode()) cache_folder = manifest.get_o3de_cache_folder() - engine = cache_folder / str(repo_sha256.hexdigest() + '.json') - print(f'{engine_uri}/engine.json cached as:') + manifest_json_path = cache_folder / str(repo_sha256.hexdigest() + '.json') else: - engine_json = pathlib.Path(engine_uri).resolve() / 'engine.json' + manifest_json_path = pathlib.Path(manifest_uri).resolve() / json_filename - with engine_json.open('r') as f: - try: - engine_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{engine_json} failed to load: {str(e)}') - else: - print(engine_json) - print(json.dumps(engine_json_data, indent=4)) - print('\n') + json_data = get_json_func(**{get_json_data_kwargs: manifest_json_path}) + if json_data: + print(manifest_json_path) + print(json.dumps(json_data, indent=4) + '\n') + return 0 -def print_projects_data(projects_data: dict) -> None: - print('\n') - print("Projects================================================") - for project_uri in projects_data: - # if it's not local it should be in the cache - parsed_uri = urllib.parse.urlparse(project_uri) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - repo_sha256 = hashlib.sha256(project_uri.encode()) - cache_folder = manifest.get_o3de_cache_folder() - project_json = cache_folder / str(repo_sha256.hexdigest() + '.json') - else: - project_json = pathlib.Path(project_uri).resolve() / 'project.json' - - with project_json.open('r') as f: - try: - project_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{project_json} failed to load: {str(e)}') - else: - print(project_json) - print(json.dumps(project_json_data, indent=4)) - print('\n') - - -def print_gems_data(gems_data: dict) -> None: - print('\n') - print("Gems================================================") - for gem_uri in gems_data: - # if it's not local it should be in the cache - parsed_uri = urllib.parse.urlparse(gem_uri) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - repo_sha256 = hashlib.sha256(gem_uri.encode()) - cache_folder = manifest.get_o3de_cache_folder() - gem_json = cache_folder / str(repo_sha256.hexdigest() + '.json') - else: - gem_json = pathlib.Path(gem_uri).resolve() / 'gem.json' - - with gem_json.open('r') as f: - try: - gem_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{gem_json} failed to load: {str(e)}') - else: - print(gem_json) - print(json.dumps(gem_json_data, indent=4)) - print('\n') - - -def print_templates_data(templates_data: dict) -> None: - print('\n') - print("Templates================================================") - for template_uri in templates_data: - # if it's not local it should be in the cache - parsed_uri = urllib.parse.urlparse(template_uri) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - repo_sha256 = hashlib.sha256(template_uri.encode()) - cache_folder = manifest.get_o3de_cache_folder() - template_json = cache_folder / str(repo_sha256.hexdigest() + '.json') - else: - template_json = pathlib.Path(template_uri).resolve() / 'template.json' - - with template_json.open('r') as f: - try: - template_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{template_json} failed to load: {str(e)}') - else: - print(template_json) - print(json.dumps(template_json_data, indent=4)) - print('\n') - - -def print_repos_data(repos_data: dict) -> None: +def print_repos_data(repos_data: dict) -> int: print('\n') print("Repos================================================") cache_folder = manifest.get_o3de_cache_folder() @@ -251,29 +284,16 @@ def print_repos_data(repos_data: dict) -> None: print(cache_file) print(json.dumps(repo_json_data, indent=4)) print('\n') - - -def print_restricted_data(restricted_data: dict) -> None: - print('\n') - print("Restricted================================================") - for restricted_path in restricted_data: - restricted_json = pathlib.Path(restricted_path).resolve() / 'restricted.json' - with restricted_json.open('r') as f: - try: - restricted_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{restricted_json} failed to load: {str(e)}') - else: - print(restricted_json) - print(json.dumps(restricted_json_data, indent=4)) - print('\n') + return 0 def register_show_repos(verbose: int) -> None: - repos_data = get_repos() + repos_data = manifest.get_repos() print(json.dumps(repos_data, indent=4)) + if verbose > 0: - print_repos_data(repos_data) + return print_repos_data(repos_data) == 0 + return 0 def register_show(verbose: int) -> None: @@ -281,13 +301,15 @@ def register_show(verbose: int) -> None: print(f"{manifest.get_o3de_manifest()}:") print(json.dumps(json_data, indent=4)) + result = True if verbose > 0: - print_engines_data(manifest.get_engines()) - print_projects_data(manifest.get_all_projects()) - print_gems_data(manifest.get_gems()) - print_templates_data(manifest.get_all_templates()) - print_restricted_data(manifest.get_all_restricted()) - print_repos_data(manifest.get_repos()) + result = print_manifest_json_data(manifest.get_engines()) == 0 and result + result = print_manifest_json_data(manifest.get_all_projects()) == 0 and result + result = print_manifest_json_data(manifest.get_gems()) == 0 and result + result = print_manifest_json_data(manifest.get_all_templates()) == 0 and result + result = print_manifest_json_data(manifest.get_all_restricted()) == 0 and result + result = print_repos_data(manifest.get_repos()) == 0 and result + return 0 if result else 1 def _run_register_show(args: argparse) -> int: @@ -295,75 +317,53 @@ def _run_register_show(args: argparse) -> int: manifest.override_home_folder = args.override_home_folder if args.this_engine: - print_this_engine(args.verbose) - return 0 - + return print_this_engine(args.verbose) elif args.engines: - print_engines(args.verbose) - return 0 + return print_engines(args.verbose) elif args.projects: - print_projects(args.verbose) - return 0 + return print_projects(args.verbose) elif args.gems: - print_gems(args.verbose) - return 0 + return print_gems(args.verbose) elif args.templates: - print_templates(args.verbose) - return 0 + return print_templates(args.verbose) elif args.repos: - register_show_repos(args.verbose) - return 0 + return register_show_repos(args.verbose) elif args.restricted: - print_restricted(args.verbose) - return 0 + return print_restricted(args.verbose) elif args.engine_projects: - print_engine_projects(args.verbose) - return 0 + return print_engine_projects(args.verbose) elif args.engine_gems: - print_engine_gems(args.verbose) - return 0 - elif args.engine_templates: - print_engine_templates(args.verbose) - return 0 - elif args.engine_restricted: - print_engine_restricted(args.verbose) - return 0 + return print_engine_gems(args.verbose) elif args.engine_external_subdirectories: - print_engine_external_subdirectories(args.verbose) - return 0 + return print_engine_external_subdirectories() + elif args.engine_templates: + return print_engine_templates(args.verbose) + elif args.engine_restricted: + return print_engine_restricted(args.verbose) + + elif args.project_gems: + return print_project_gems(args.verbose, args.project_path, args.project_name) + elif args.project_external_subdirectories: + return print_project_external_subdirectories(args.project_path, args.project_name) + elif args.project_templates: + return print_project_templates(args.verbose, args.project_path, args.project_name) + elif args.project_restricted: + return print_project_restricted(args.verbose, args.project_path, args.project_name) elif args.all_projects: - print_all_projects(args.verbose) - return 0 + return print_all_projects(args.verbose) elif args.all_gems: - print_all_gems(args.verbose) - return 0 + return print_all_gems(args.verbose) + elif args.all_external_subdirectories: + return print_all_external_subdirectories() elif args.all_templates: - print_all_templates(args.verbose) - return 0 + return print_all_templates(args.verbose) elif args.all_restricted: - print_all_restricted(args.verbose) - return 0 + return print_all_restricted(args.verbose) - elif args.downloadables: - print_downloadables(args.verbose) - return 0 - if args.downloadable_engines: - print_downloadable_engines(args.verbose) - return 0 - elif args.downloadable_projects: - print_downloadable_projects(args.verbose) - return 0 - elif args.downloadable_gems: - print_downloadable_gems(args.verbose) - return 0 - elif args.downloadable_templates: - print_downloadable_templates(args.verbose) - return 0 else: - register_show(args.verbose) - return 0 + return register_show(args.verbose) def add_parser_args(parser): @@ -376,78 +376,84 @@ def add_parser_args(parser): group = parser.add_mutually_exclusive_group(required=False) group.add_argument('-te', '--this-engine', action='store_true', required=False, default=False, - help='Just the local engines.') + help='Output the current engine path.') group.add_argument('-e', '--engines', action='store_true', required=False, default=False, - help='Just the local engines.') + help='Output the engines registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-p', '--projects', action='store_true', required=False, default=False, - help='Just the local projects.') + help='Output the projects registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-g', '--gems', action='store_true', required=False, default=False, - help='Just the local gems.') + help='Output the gems registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-t', '--templates', action='store_true', required=False, default=False, - help='Just the local templates.') + help='Output the templates registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-r', '--repos', action='store_true', required=False, default=False, - help='Just the local repos. Ignores repos.') + help='Output the repos registered in the global ~/.o3de/o3de_manifest.json. Ignores repos.') group.add_argument('-rs', '--restricted', action='store_true', required=False, default=False, - help='The local restricted folders.') + help='Output the restricted directories registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-ep', '--engine-projects', action='store_true', required=False, default=False, - help='Just the local projects. Ignores repos.') + help='Output the projects registered in the current engine engine.json. Ignores repos.') group.add_argument('-eg', '--engine-gems', action='store_true', required=False, default=False, - help='Just the local gems. Ignores repos') + help='Output the gems registered in the current engine engine.json. Ignores repos') group.add_argument('-et', '--engine-templates', action='store_true', required=False, default=False, - help='Just the local templates. Ignores repos.') + help='Output the templates registered in the current engine engine.json. Ignores repos.') group.add_argument('-ers', '--engine-restricted', action='store_true', required=False, default=False, - help='The restricted folders.') - group.add_argument('-x', '--engine-external-subdirectories', action='store_true', required=False, + help='Output the restricted directories registered in the current engine engine.json.') + group.add_argument('-ees', '--engine-external-subdirectories', action='store_true', required=False, default=False, - help='The external subdirectories.') + help='Output the external subdirectories registered in the current engine engine.json.') + + group.add_argument('-pg', '--project-gems', action='store_true', + default=False, + help='Returns the gems registered with the project.json.') + group.add_argument('-pt', '--project-templates', action='store_true', + default=False, + help='Returns the templates registered with the project.json.') + group.add_argument('-prs', '--project-restricted', action='store_true', + default=False, + help='Returns the restricted directories registered with the project.json.') + group.add_argument('-pes', '--project-external-subdirectories', action='store_true', + default=False, + help='Returns the external subdirectories register with the project.json.') group.add_argument('-ap', '--all-projects', action='store_true', required=False, default=False, - help='Just the local projects. Ignores repos.') + help='Output all projects registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos.') group.add_argument('-ag', '--all-gems', action='store_true', required=False, default=False, - help='Just the local gems. Ignores repos') + help='Output all gems registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos') group.add_argument('-at', '--all-templates', action='store_true', required=False, default=False, - help='Just the local templates. Ignores repos.') - group.add_argument('-ars', '--all-restricted', action='store_true', required=False, + help='Output all templates registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos.') + group.add_argument('-ares', '--all-restricted', action='store_true', required=False, default=False, - help='The restricted folders.') - - group.add_argument('-d', '--downloadables', action='store_true', required=False, + help='Output all restricted directory registered in the ~/.o3de/o3de_manifest.json and the current engine.json.') + group.add_argument('-aes', '--all-external-subdirectories', action='store_true', default=False, - help='Combine all repos into a single list of resources.') - group.add_argument('-de', '--downloadable-engines', action='store_true', required=False, - default=False, - help='Combine all repos engines into a single list of resources.') - group.add_argument('-dp', '--downloadable-projects', action='store_true', required=False, - default=False, - help='Combine all repos projects into a single list of resources.') - group.add_argument('-dg', '--downloadable-gems', action='store_true', required=False, - default=False, - help='Combine all repos gems into a single list of resources.') - group.add_argument('-dt', '--downloadable-templates', action='store_true', required=False, - default=False, - help='Combine all repos templates into a single list of resources.') + help='Output all external subdirectories registered in the ~/.o3de/o3de_manifest.json and the current engine.json.') parser.add_argument('-v', '--verbose', action='count', required=False, - default=0, - help='How verbose do you want the output to be.') + default=0, + help='How verbose do you want the output to be.') + + project_group = parser.add_mutually_exclusive_group(required=False) + project_group.add_argument('-pp', '--project-path', type=pathlib.Path, + help='The path to a project.') + project_group.add_argument('-pn', '--project-name', type=str, + help='The name of a project.') parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, - help='By default the home folder is the user folder, override it to this folder.') + help='By default the home folder is the user folder, override it to this folder.') parser.set_defaults(func=_run_register_show) diff --git a/scripts/o3de/tests/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt index 0526c7740d..82b994e387 100644 --- a/scripts/o3de/tests/CMakeLists.txt +++ b/scripts/o3de/tests/CMakeLists.txt @@ -34,3 +34,10 @@ ly_add_pytest( TEST_SUITE smoke EXCLUDE_TEST_RUN_TARGET_FROM_IDE ) + +ly_add_pytest( + NAME o3de_manifest + PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_manifest.py + TEST_SUITE smoke + EXCLUDE_TEST_RUN_TARGET_FROM_IDE +) diff --git a/scripts/o3de/tests/unit_test_manifest.py b/scripts/o3de/tests/unit_test_manifest.py new file mode 100644 index 0000000000..98430c227b --- /dev/null +++ b/scripts/o3de/tests/unit_test_manifest.py @@ -0,0 +1,111 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +import argparse +import json +import logging +import pytest +import pathlib +from unittest.mock import patch + +from o3de import manifest + + +@pytest.mark.parametrize("valid_project_json_paths, valid_gem_json_paths", [ + pytest.param([pathlib.Path('D:/o3de/Templates/DefaultProject/Template/project.json')], + [pathlib.Path('D:/o3de/Templates/DefaultGem/Template/gem.json')]) +]) +class TestGetTemplatesForCreation: + @staticmethod + def get_templates() -> list: + return [] + + @staticmethod + def get_project_templates() -> list: + return [] + + @staticmethod + def get_engine_templates() -> list: + return [pathlib.Path('D:/o3de/Templates/DefaultProject'), pathlib.Path('D:/o3de/Templates/DefaultGem')] + + + @pytest.mark.parametrize("expected_template_paths", [ + pytest.param([]) + ] + ) + def test_get_templates_for_generic_creation(self, valid_project_json_paths, valid_gem_json_paths, + expected_template_paths): + def validate_project_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_project_json_paths + + def validate_gem_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_gem_json_paths + + with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \ + patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates)\ + as get_project_templates_patch, \ + patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates)\ + as get_engine_templates_patch, \ + patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json,\ + patch('o3de.validation.valid_o3de_project_json', side_effect=validate_project_json) as validate_project_json,\ + patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json: + templates = manifest.get_templates_for_generic_creation() + assert templates == expected_template_paths + + + @pytest.mark.parametrize("expected_template_paths", [ + pytest.param([pathlib.Path('D:/o3de/Templates/DefaultProject')]) + ] + ) + def test_get_templates_for_gem_creation(self, valid_project_json_paths, valid_gem_json_paths, + expected_template_paths): + def validate_project_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_project_json_paths + + def validate_gem_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_gem_json_paths + + with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \ + patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates) \ + as get_project_templates_patch, \ + patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates) \ + as get_engine_templates_patch, \ + patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json, \ + patch('o3de.validation.valid_o3de_project_json', + side_effect=validate_project_json) as validate_project_json, \ + patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json: + templates = manifest.get_templates_for_project_creation() + assert templates == expected_template_paths + + + @pytest.mark.parametrize("expected_template_paths", [ + pytest.param([pathlib.Path('D:/o3de/Templates/DefaultGem')]) + ] + ) + def test_get_templates_for_project_creation(self, valid_project_json_paths, valid_gem_json_paths, + expected_template_paths): + def validate_project_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_project_json_paths + + def validate_gem_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_gem_json_paths + + with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \ + patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates) \ + as get_project_templates_patch, \ + patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates) \ + as get_engine_templates_patch, \ + patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json, \ + patch('o3de.validation.valid_o3de_project_json', + side_effect=validate_project_json) as validate_project_json, \ + patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json: + templates = manifest.get_templates_for_gem_creation() + assert templates == expected_template_paths \ No newline at end of file diff --git a/scripts/o3de/tests/unit_test_utils.py b/scripts/o3de/tests/unit_test_utils.py index e7d59b507b..4fe22b1f72 100755 --- a/scripts/o3de/tests/unit_test_utils.py +++ b/scripts/o3de/tests/unit_test_utils.py @@ -11,7 +11,7 @@ import pytest -from . import utils +from o3de import utils @pytest.mark.parametrize( "value, expected_result", [ From deb3c5e74a9cfa1725c77711bc584952b4231a79 Mon Sep 17 00:00:00 2001 From: cgalvan Date: Thu, 3 Jun 2021 18:20:59 -0500 Subject: [PATCH 29/45] [LYN-2446] Implemented support for duplicating instances. (#1097) * [LYN-2446] Implemented support for duplicating instances. * [LYN-2446] Addressed PR feedback. * [LYN-2446] Addressed additional PR feedback. --- .../Prefab/Instance/Instance.h | 4 +- .../Instance/InstanceUpdateExecutor.cpp | 24 ++ .../Prefab/PrefabPublicHandler.cpp | 290 +++++++++++++----- .../Prefab/PrefabPublicHandler.h | 27 ++ 4 files changed, 259 insertions(+), 86 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index 4a69ade6d2..d14203e2e5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -174,6 +174,8 @@ namespace AzToolsFramework static EntityAlias GenerateEntityAlias(); AliasPath GetAbsoluteInstanceAliasPath() const; + static InstanceAlias GenerateInstanceAlias(); + protected: /** * Gets the entities owned by this instance @@ -190,8 +192,6 @@ namespace AzToolsFramework bool RegisterEntity(const AZ::EntityId& entityId, const EntityAlias& entityAlias); AZStd::unique_ptr DetachEntity(const EntityAlias& entityAlias); - static InstanceAlias GenerateInstanceAlias(); - // Provide access to private data members in the serializer friend class JsonInstanceSerializer; friend class InstanceEntityIdMapper; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp index e0d29f2ab1..6194adf784 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp @@ -152,6 +152,30 @@ namespace AzToolsFramework Instance::EntityList newEntities; if (PrefabDomUtils::LoadInstanceFromPrefabDom(*instanceToUpdate, newEntities, currentTemplate.GetPrefabDom())) { + // If a link was created for a nested instance before the changes were propagated, + // then we associate it correctly here + instanceToUpdate->GetNestedInstances([&](AZStd::unique_ptr& nestedInstance) { + if (nestedInstance->GetLinkId() != InvalidLinkId) + { + return; + } + + for (auto linkId : currentTemplate.GetLinks()) + { + LinkReference nestedLink = m_prefabSystemComponentInterface->FindLink(linkId); + if (!nestedLink.has_value()) + { + continue; + } + + if (nestedLink->get().GetInstanceName() == nestedInstance->GetInstanceAlias()) + { + nestedInstance->SetLinkId(linkId); + break; + } + } + }); + AzToolsFramework::EditorEntityContextRequestBus::Broadcast( &AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded, newEntities); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 27c812ff9d..4656dcf48f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -899,16 +899,29 @@ namespace AzToolsFramework if (!EntitiesBelongToSameInstance(entityIds)) { - return AZ::Failure(AZStd::string("Cannot duplicate multiple " - "entities belonging to different instances with one operation.")); + return AZ::Failure(AZStd::string("Cannot duplicate multiple entities belonging to different instances with one operation." + "Change your selection to contain entities in the same instance.")); } // We've already verified the entities are all owned by the same instance, // so we can just retrieve our instance from the first entity in the list. - InstanceOptionalReference commonEntityOwningInstance = GetOwnerInstanceByEntityId(entityIds[0]); - AZ_Assert( - commonEntityOwningInstance.has_value(), - "Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided"); + AZ::EntityId firstEntityIdToDuplicate = entityIds[0]; + InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDuplicate); + if (!commonOwningInstance.has_value()) + { + return AZ::Failure(AZStd::string("Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided.")); + } + + // If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you + // cannot duplicate an instance from itself. + if (commonOwningInstance->get().GetContainerEntityId() == firstEntityIdToDuplicate) + { + commonOwningInstance = commonOwningInstance->get().GetParentInstance(); + } + if (!commonOwningInstance.has_value()) + { + return AZ::Failure(AZStd::string("Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided.")); + } // This will cull out any entities that have ancestors in the list, since we will end up duplicating // the full nested hierarchy with what is returned from RetrieveAndSortPrefabEntitiesAndInstances @@ -921,105 +934,63 @@ namespace AzToolsFramework { AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "DuplicateEntitiesInInstance::UndoCaptureAndDuplicateEntities"); - // Take a snapshot of the instance DOM before we manipulate it - Prefab::PrefabDom instanceDomBefore; - m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, commonEntityOwningInstance->get()); - AZStd::vector entities; AZStd::vector instances; - // Gather all entities/instances in the hierarchy, but don't detach them because we are duplicating not deleting. EntityList inputEntityList = EntityIdSetToEntityList(duplicationSet); - bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonEntityOwningInstance->get(), entities, instances); + bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances); if (!success) { return AZ::Failure(AZStd::string("Failed to retrieve entities and instances from the given list of entity ids for duplication")); } - // Make a copy of our before instance DOM where we will add our duplicated entities - Prefab::PrefabDom instanceDomAfter; + // Take a snapshot of the instance DOM before we manipulate it + PrefabDom instanceDomBefore; + m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, commonOwningInstance->get()); + + // Make a copy of our before instance DOM where we will add our duplicated entities and/or instances + PrefabDom instanceDomAfter; instanceDomAfter.CopyFrom(instanceDomBefore, instanceDomAfter.GetAllocator()); - AZStd::unordered_map oldAliasToNewAliasMap; - AZStd::unordered_map aliasToEntityDomMap; + EntityIdList duplicatedEntityAndInstanceIds; - for (AZ::Entity* entity : entities) - { - EntityAliasOptionalReference oldAliasRef = commonEntityOwningInstance->get().GetEntityAlias(entity->GetId()); - AZ_Assert(oldAliasRef.has_value(), "No alias found for Entity in the DOM"); - EntityAlias oldAlias = oldAliasRef.value(); + // Duplicate any nested entities and instances as requested + AZStd::unordered_map newInstanceAliasToOldInstanceMap; + DuplicateNestedEntitiesInInstance(commonOwningInstance->get(), + entities, instanceDomAfter, duplicatedEntityAndInstanceIds); + DuplicateNestedInstancesInInstance(commonOwningInstance->get(), + instances, instanceDomAfter, duplicatedEntityAndInstanceIds, + newInstanceAliasToOldInstanceMap); - // Give this the outer allocator so that the memory reference will be valid when - // it gets used for AddMember - Prefab::PrefabDom entityDomBefore(&instanceDomAfter.GetAllocator()); - m_instanceToTemplateInterface->GenerateDomForEntity(entityDomBefore, *entity); - - // Keep track of the old alias <-> new alias mapping for this duplicated entity - // so we can fixup references later - EntityAlias newEntityAlias = Instance::GenerateEntityAlias(); - oldAliasToNewAliasMap.insert(AZStd::make_pair(oldAlias, newEntityAlias)); - - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - entityDomBefore.Accept(writer); - - // Store our duplicated Entity DOM with its new alias as a string - // so that we can fixup entity alias references before adding it - // to the Entities member of our instance DOM - QString entityDomString(buffer.GetString()); - aliasToEntityDomMap.insert(AZStd::make_pair(newEntityAlias, entityDomString)); - } - - auto entitiesIter = instanceDomAfter.FindMember(PrefabDomUtils::EntitiesName); - AZ_Assert(entitiesIter != instanceDomAfter.MemberEnd(), "Instance DOM missing the Entities member."); - - // Now that all the duplicated Entity DOMs have been created, we need to iterate - // through them and replace any previous EntityAlias references with the new ones. - // These are more than just parent entity references for nested entities, this will - // also cover any EntityId references that were made in the components between them. - for (auto aliasEntityPair : aliasToEntityDomMap) - { - EntityAlias newEntityAlias = aliasEntityPair.first; - QString newEntityDomString = aliasEntityPair.second; - - // Replace all of the old alias references with the new ones - // We bookend the aliases with \" and also with a / as an extra precaution to prevent - // inadvertently replacing a matching string vs. where an actual EntityId is expected - // This will cover both cases where an alias could be used in a normal entity vs. an instance - for (auto aliasMapIter : oldAliasToNewAliasMap) - { - ReplaceOldAliases(newEntityDomString, aliasMapIter.first, aliasMapIter.second); - } - - // Create the new Entity DOM from parsing the JSON string - Prefab::PrefabDom entityDomAfter(&instanceDomAfter.GetAllocator()); - entityDomAfter.Parse(newEntityDomString.toUtf8().constData()); - - // Add the new Entity DOM to the Entities member of the instance - rapidjson::Value aliasName(newEntityAlias.c_str(), newEntityAlias.length(), instanceDomAfter.GetAllocator()); - entitiesIter->value.AddMember(AZStd::move(aliasName), entityDomAfter, instanceDomAfter.GetAllocator()); - } - - PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity duplication"); + PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication"); command->SetParent(undoBatch.GetUndoBatch()); - command->Capture(instanceDomBefore, instanceDomAfter, commonEntityOwningInstance->get().GetTemplateId()); - command->RunRedo(); + command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId()); + command->Redo(); - EntityIdList duplicatedEntityIds; - for (auto aliasMapIter : oldAliasToNewAliasMap) + // Create links for our duplicated instances (if any were duplicated) + for (auto [newInstanceAlias, oldInstance] : newInstanceAliasToOldInstanceMap) { - EntityAlias newEntityAlias = aliasMapIter.second; + LinkId oldLinkId = oldInstance->GetLinkId(); + auto linkRef = m_prefabSystemComponentInterface->FindLink(oldLinkId); + AZ_Assert( + linkRef.has_value(), "Unable to find link with id '%llu' during instance duplication.", + oldLinkId); - AliasPath absoluteEntityPath = commonEntityOwningInstance->get().GetAbsoluteInstanceAliasPath(); - absoluteEntityPath.Append(newEntityAlias); + PrefabDomValueReference linkPatches = linkRef->get().GetLinkPatches(); + AZ_Assert( + linkPatches.has_value(), "Link with id '%llu' is missing patches.", + oldLinkId); - AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteEntityPath); - duplicatedEntityIds.push_back(newEntityId); + PrefabDom linkPatchesCopy; + linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator()); + + m_prefabSystemComponentInterface->CreateLink( + commonOwningInstance->get().GetTemplateId(), oldInstance->GetTemplateId(), newInstanceAlias, linkPatchesCopy); } - // Select the duplicated entities - auto selectionUndo = aznew SelectionCommand(duplicatedEntityIds, "Select Duplicated Entities"); + // Select the duplicated entities/instances + auto selectionUndo = aznew SelectionCommand(duplicatedEntityAndInstanceIds, "Select Duplicated Entities/Instances"); selectionUndo->SetParent(undoBatch.GetUndoBatch()); ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, selectionUndo); } @@ -1508,8 +1479,159 @@ namespace AzToolsFramework return true; } + void PrefabPublicHandler::DuplicateNestedEntitiesInInstance(Instance& commonOwningInstance, + const AZStd::vector& entities, PrefabDom& domToAddDuplicatedEntitiesUnder, + EntityIdList& duplicatedEntityIds) + { + if (entities.empty()) + { + return; + } + + AZStd::unordered_map oldAliasToNewAliasMap; + AZStd::unordered_map aliasToEntityDomMap; + + for (AZ::Entity* entity : entities) + { + EntityAliasOptionalReference oldAliasRef = commonOwningInstance.GetEntityAlias(entity->GetId()); + AZ_Assert(oldAliasRef.has_value(), "No alias found for Entity in the DOM"); + EntityAlias oldAlias = oldAliasRef.value(); + + // Give this the outer allocator so that the memory reference will be valid when + // it gets used for AddMember + PrefabDom entityDomBefore(&domToAddDuplicatedEntitiesUnder.GetAllocator()); + m_instanceToTemplateInterface->GenerateDomForEntity(entityDomBefore, *entity); + + // Keep track of the old alias <-> new alias mapping for this duplicated entity + // so we can fixup references later + EntityAlias newEntityAlias = Instance::GenerateEntityAlias(); + oldAliasToNewAliasMap.emplace(oldAlias, newEntityAlias); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + entityDomBefore.Accept(writer); + + // Store our duplicated Entity DOM with its new alias as a string + // so that we can fixup entity alias references before adding it + // to the Entities member of our instance DOM + QString entityDomString(buffer.GetString()); + aliasToEntityDomMap.emplace(newEntityAlias, entityDomString); + } + + auto entitiesIter = domToAddDuplicatedEntitiesUnder.FindMember(PrefabDomUtils::EntitiesName); + AZ_Assert(entitiesIter != domToAddDuplicatedEntitiesUnder.MemberEnd(), "Instance DOM missing the Entities member."); + + // Now that all the duplicated Entity DOMs have been created, we need to iterate + // through them and replace any previous EntityAlias references with the new ones. + // These are more than just parent entity references for nested entities, this will + // also cover any EntityId references that were made in the components between them. + for (auto [newEntityAlias, newEntityDomString] : aliasToEntityDomMap) + { + // Replace all of the old alias references with the new ones + for (auto [oldAlias, newAlias] : oldAliasToNewAliasMap) + { + ReplaceOldAliases(newEntityDomString, oldAlias, newAlias); + } + + // Create the new Entity DOM from parsing the JSON string + PrefabDom entityDomAfter(&domToAddDuplicatedEntitiesUnder.GetAllocator()); + entityDomAfter.Parse(newEntityDomString.toUtf8().constData()); + + // Add the new Entity DOM to the Entities member of the instance + rapidjson::Value aliasName(newEntityAlias.c_str(), newEntityAlias.length(), domToAddDuplicatedEntitiesUnder.GetAllocator()); + entitiesIter->value.AddMember(AZStd::move(aliasName), entityDomAfter, domToAddDuplicatedEntitiesUnder.GetAllocator()); + } + + for (auto aliasMapIter : oldAliasToNewAliasMap) + { + EntityAlias newEntityAlias = aliasMapIter.second; + + AliasPath absoluteEntityPath = commonOwningInstance.GetAbsoluteInstanceAliasPath(); + absoluteEntityPath.Append(newEntityAlias); + + AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteEntityPath); + duplicatedEntityIds.push_back(newEntityId); + } + } + + void PrefabPublicHandler::DuplicateNestedInstancesInInstance(Instance& commonOwningInstance, + const AZStd::vector& instances, PrefabDom& domToAddDuplicatedInstancesUnder, + EntityIdList& duplicatedEntityIds, AZStd::unordered_map& newInstanceAliasToOldInstanceMap) + { + if (instances.empty()) + { + return; + } + + AZStd::unordered_map oldInstanceAliasToNewInstanceAliasMap; + AZStd::unordered_map aliasToInstanceDomMap; + + for (auto instance : instances) + { + PrefabDom nestedInstanceDomBefore; + m_instanceToTemplateInterface->GenerateDomForInstance(nestedInstanceDomBefore, *instance); + + // Keep track of the old alias <-> new alias mapping for this duplicated instance + // so we can fixup references later + InstanceAlias oldAlias = instance->GetInstanceAlias(); + InstanceAlias newInstanceAlias = Instance::GenerateInstanceAlias(); + oldInstanceAliasToNewInstanceAliasMap.emplace(oldAlias, newInstanceAlias); + + // Keep track of our new instance alias with the Instance it was duplicated from, + // so that after all instances are duplicated, we can go back and create links for them + newInstanceAliasToOldInstanceMap.emplace(newInstanceAlias, instance); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + nestedInstanceDomBefore.Accept(writer); + + // Store our duplicated Instance DOM with its new alias as a string + // so that we can fixup instance alias references before adding it + // to the Instances member of our instance DOM + QString instanceDomString(buffer.GetString()); + aliasToInstanceDomMap.emplace(newInstanceAlias, instanceDomString); + } + + auto instancesIter = domToAddDuplicatedInstancesUnder.FindMember(PrefabDomUtils::InstancesName); + AZ_Assert(instancesIter != domToAddDuplicatedInstancesUnder.MemberEnd(), "Instance DOM missing the Instances member."); + + // Now that all the duplicated Instance DOMs have been created, we need to iterate + // through them and replace any previous InstanceAlias references with the new ones. + for (auto [newInstanceAlias, newInstanceDomString]: aliasToInstanceDomMap) + { + // Replace all of the old alias references with the new ones + for (auto [oldAlias, newAlias] : oldInstanceAliasToNewInstanceAliasMap) + { + ReplaceOldAliases(newInstanceDomString, oldAlias, newAlias); + } + + // Create the new Instance DOM from parsing the JSON string + PrefabDom nestedInstanceDomAfter(&domToAddDuplicatedInstancesUnder.GetAllocator()); + nestedInstanceDomAfter.Parse(newInstanceDomString.toUtf8().constData()); + + // Add the new Instance DOM to the Instances member of the instance + rapidjson::Value aliasName(newInstanceAlias.c_str(), newInstanceAlias.length(), domToAddDuplicatedInstancesUnder.GetAllocator()); + instancesIter->value.AddMember(AZStd::move(aliasName), nestedInstanceDomAfter, domToAddDuplicatedInstancesUnder.GetAllocator()); + } + + for (auto aliasMapIter : oldInstanceAliasToNewInstanceAliasMap) + { + InstanceAlias newInstanceAlias = aliasMapIter.second; + + AliasPath absoluteInstancePath = commonOwningInstance.GetAbsoluteInstanceAliasPath(); + absoluteInstancePath.Append(newInstanceAlias); + + AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteInstancePath); + duplicatedEntityIds.push_back(newEntityId); + } + } + void PrefabPublicHandler::ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias) { + // Replace all of the old alias references with the new ones + // We bookend the aliases with \" and also with a / as an extra precaution to prevent + // inadvertently replacing a matching string vs. where an actual EntityId is expected + // This will cover both cases where an alias could be used in a normal entity vs. an instance QString oldAliasQuotes = QString("\"%1\"").arg(oldAlias.data()); QString newAliasQuotes = QString("\"%1\"").arg(newAlias.data()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index 99fe8e5b67..167791d1c1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -73,6 +73,33 @@ namespace AzToolsFramework InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const; bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const; + + /** + * Duplicate a list of entities owned by a common owning instance by directly + * copying/modifying their entries in the instance DOM + * + * \param commonOwningInstance The common owning instance of all the entities being duplicated. + * \param entities The list of Entities that will be duplicated. + * \param domToAddDuplicatedEntitiesUnder The DOM of the common owning instance where the duplicated + * entity DOM values will be added to. + * \param duplicatedEntityIds A list of EntityIds corresponding to the entities that were duplicated. + */ + void DuplicateNestedEntitiesInInstance(Instance& commonOwningInstance, + const AZStd::vector& entities, PrefabDom& domToAddDuplicatedEntitiesUnder, + EntityIdList& duplicatedEntityIds); + /** + * Duplicate a list of instances owned by a common owning instance by directly + * copying/modifying their entries in the instance DOM + * + * \param commonOwningInstance The common owning instance of all the instances being duplicated. + * \param entities The list of Instances that will be duplicated. + * \param domToAddDuplicatedInstancesUnder The DOM of the common owning instance where the duplicated + * instance DOM values will be added to. + * \param duplicatedEntityIds A list of EntityIds corresponding to the instances that were duplicated. + */ + void DuplicateNestedInstancesInInstance(Instance& commonOwningInstance, + const AZStd::vector& instances, PrefabDom& domToAddDuplicatedInstancesUnder, + EntityIdList& duplicatedEntityIds, AZStd::unordered_map& newInstanceAliasToOldInstanceMap); /** * Applies the correct transform changes to the container entity based on the parent and child entities provided, and returns an appropriate patch. From 08a2e50ee34ad1a77009334552a1bd94a59ec7a3 Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 16:28:15 -0700 Subject: [PATCH 30/45] [default_3rdparty] missed updating a call to register --- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 837235cedc..ee4e30846b 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -572,6 +572,7 @@ namespace O3DE::ProjectManager pybind11::none(), // default_gems_folder pybind11::none(), // default_templates_folder pybind11::none(), // default_restricted_folder + pybind11::none(), // default_third_party_folder pybind11::none(), // external_subdir_engine_path pybind11::none(), // external_subdir_project_path true, // remove From 29ac17a090912f483ddb1d6853eea18af8058324 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 3 Jun 2021 18:05:05 -0700 Subject: [PATCH 31/45] SPEC-7135 Provide a method to re-trigger compiler detection for changes that require it (#1092) * SPEC-7135 Provide a method to re-trigger compiler detection for changes that require it * removing check (is wrong and is not necessary) * Invert existance check * add empty lines at the end * Clean is triggering on each build * clearing if the variable is false * test code to understand what is going on... * yeap, looks good * handling "false" in linux/mac * fix for linux/mac * Fixing typos --- scripts/build/Platform/Linux/build_linux.sh | 3 +- scripts/build/Platform/Linux/clean_linux.sh | 37 ++++++++++++++++- scripts/build/Platform/Mac/build_mac.sh | 1 + scripts/build/Platform/Mac/clean_mac.sh | 37 ++++++++++++++++- .../build/Platform/Windows/build_windows.cmd | 3 +- .../build/Platform/Windows/clean_windows.cmd | 41 ++++++++++++++++++- 6 files changed, 116 insertions(+), 6 deletions(-) diff --git a/scripts/build/Platform/Linux/build_linux.sh b/scripts/build/Platform/Linux/build_linux.sh index d96fd32371..ef1b1dcb96 100755 --- a/scripts/build/Platform/Linux/build_linux.sh +++ b/scripts/build/Platform/Linux/build_linux.sh @@ -14,6 +14,7 @@ set -o errexit # exit on the first failure encountered BASEDIR=$(dirname "$0") source $BASEDIR/env_linux.sh +source $BASEDIR/clean_linux.sh mkdir -p ${OUTPUT_DIRECTORY} SOURCE_DIRECTORY=${PWD} @@ -46,4 +47,4 @@ fi echo [ci_build] cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(grep -c processor /proc/cpuinfo) -- ${CMAKE_NATIVE_BUILD_ARGS} cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(grep -c processor /proc/cpuinfo) -- ${CMAKE_NATIVE_BUILD_ARGS} -popd \ No newline at end of file +popd diff --git a/scripts/build/Platform/Linux/clean_linux.sh b/scripts/build/Platform/Linux/clean_linux.sh index a21527d319..a314859877 100755 --- a/scripts/build/Platform/Linux/clean_linux.sh +++ b/scripts/build/Platform/Linux/clean_linux.sh @@ -12,6 +12,16 @@ set -o errexit # exit on the first failure encountered +# Jenkins defines environment variables for parameters and passes "false" to variables +# that are not set. Here we clear them if they are false so we can also just define them +# from command line +if [[ "${CLEAN_ASSETS}" == "false" ]]; then + CLEAN_ASSETS= +fi +if [[ "${CLEAN_OUTPUT_DIRECTORY}" == "false" ]]; then + CLEAN_OUTPUT_DIRECTORY= +fi + if [[ -n "$CLEAN_ASSETS" ]]; then echo "[ci_build] CLEAN_ASSETS option set" for project in $(echo $CMAKE_LY_PROJECTS | sed "s/;/ /g") @@ -23,10 +33,35 @@ if [[ -n "$CLEAN_ASSETS" ]]; then done fi +# If the node label changes, we issue a clean output since node changes can change SDK/CMake/toolchains/etc +LAST_CONFIGURE_NODE_LABEL_FILE=ci_last_node_label.txt +if [[ -n "$NODE_LABEL" ]]; then + if [[ -d $OUTPUT_DIRECTORY ]]; then + pushd $OUTPUT_DIRECTORY + if [[ -e ${LAST_CONFIGURE_NODE_LABEL_FILE} ]]; then + LAST_NODE_LABEL=$(<${LAST_CONFIGURE_NODE_LABEL_FILE}) + else + LAST_NODE_LABEL= + fi + # Detect if the node label has changed + if [[ "${LAST_NODE_LABEL}" != "${NODE_LABEL}" ]]; then + echo [ci_build] Last run was done with node label \"${LAST_NODE_LABEL}\", new node label is \"${NODE_LABEL}\", forcing CLEAN_OUTPUT_DIRECTORY + CLEAN_OUTPUT_DIRECTORY=1 + fi + popd + fi +fi + if [[ -n "$CLEAN_OUTPUT_DIRECTORY" ]]; then echo "[ci_build] CLEAN_OUTPUT_DIRECTORY option set" if [[ -d $OUTPUT_DIRECTORY ]]; then echo "[ci_build] Deleting \"${OUTPUT_DIRECTORY}\"" rm -rf ${OUTPUT_DIRECTORY} fi -fi \ No newline at end of file +fi + +mkdir -p ${OUTPUT_DIRECTORY} +# Save the node label +pushd $OUTPUT_DIRECTORY +echo "${NODE_LABEL}" > ${LAST_CONFIGURE_NODE_LABEL_FILE} +popd diff --git a/scripts/build/Platform/Mac/build_mac.sh b/scripts/build/Platform/Mac/build_mac.sh index 473a968d98..4a61f97fe4 100755 --- a/scripts/build/Platform/Mac/build_mac.sh +++ b/scripts/build/Platform/Mac/build_mac.sh @@ -14,6 +14,7 @@ set -o errexit # exit on the first failure encountered BASEDIR=$(dirname "$0") source $BASEDIR/env_mac.sh +source $BASEDIR/clean_mac.sh mkdir -p ${OUTPUT_DIRECTORY} SOURCE_DIRECTORY=${PWD} diff --git a/scripts/build/Platform/Mac/clean_mac.sh b/scripts/build/Platform/Mac/clean_mac.sh index a21527d319..a314859877 100755 --- a/scripts/build/Platform/Mac/clean_mac.sh +++ b/scripts/build/Platform/Mac/clean_mac.sh @@ -12,6 +12,16 @@ set -o errexit # exit on the first failure encountered +# Jenkins defines environment variables for parameters and passes "false" to variables +# that are not set. Here we clear them if they are false so we can also just define them +# from command line +if [[ "${CLEAN_ASSETS}" == "false" ]]; then + CLEAN_ASSETS= +fi +if [[ "${CLEAN_OUTPUT_DIRECTORY}" == "false" ]]; then + CLEAN_OUTPUT_DIRECTORY= +fi + if [[ -n "$CLEAN_ASSETS" ]]; then echo "[ci_build] CLEAN_ASSETS option set" for project in $(echo $CMAKE_LY_PROJECTS | sed "s/;/ /g") @@ -23,10 +33,35 @@ if [[ -n "$CLEAN_ASSETS" ]]; then done fi +# If the node label changes, we issue a clean output since node changes can change SDK/CMake/toolchains/etc +LAST_CONFIGURE_NODE_LABEL_FILE=ci_last_node_label.txt +if [[ -n "$NODE_LABEL" ]]; then + if [[ -d $OUTPUT_DIRECTORY ]]; then + pushd $OUTPUT_DIRECTORY + if [[ -e ${LAST_CONFIGURE_NODE_LABEL_FILE} ]]; then + LAST_NODE_LABEL=$(<${LAST_CONFIGURE_NODE_LABEL_FILE}) + else + LAST_NODE_LABEL= + fi + # Detect if the node label has changed + if [[ "${LAST_NODE_LABEL}" != "${NODE_LABEL}" ]]; then + echo [ci_build] Last run was done with node label \"${LAST_NODE_LABEL}\", new node label is \"${NODE_LABEL}\", forcing CLEAN_OUTPUT_DIRECTORY + CLEAN_OUTPUT_DIRECTORY=1 + fi + popd + fi +fi + if [[ -n "$CLEAN_OUTPUT_DIRECTORY" ]]; then echo "[ci_build] CLEAN_OUTPUT_DIRECTORY option set" if [[ -d $OUTPUT_DIRECTORY ]]; then echo "[ci_build] Deleting \"${OUTPUT_DIRECTORY}\"" rm -rf ${OUTPUT_DIRECTORY} fi -fi \ No newline at end of file +fi + +mkdir -p ${OUTPUT_DIRECTORY} +# Save the node label +pushd $OUTPUT_DIRECTORY +echo "${NODE_LABEL}" > ${LAST_CONFIGURE_NODE_LABEL_FILE} +popd diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index 3e995e1905..474c1720df 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -13,6 +13,7 @@ REM SETLOCAL EnableDelayedExpansion CALL %~dp0env_windows.cmd +CALL %~dp0clean_windows.cmd IF NOT EXIST "%OUTPUT_DIRECTORY%" ( MKDIR %OUTPUT_DIRECTORY%. @@ -70,4 +71,4 @@ EXIT /b 0 :error POPD -EXIT /b 1 \ No newline at end of file +EXIT /b 1 diff --git a/scripts/build/Platform/Windows/clean_windows.cmd b/scripts/build/Platform/Windows/clean_windows.cmd index 38c1d45c21..60ad445d4d 100644 --- a/scripts/build/Platform/Windows/clean_windows.cmd +++ b/scripts/build/Platform/Windows/clean_windows.cmd @@ -12,6 +12,16 @@ REM SETLOCAL EnableDelayedExpansion +REM Jenkins defines environment variables for parameters and passes "false" to variables +REM that are not set. Here we clear them if they are false so we can also just define them +REM from command line +IF "%CLEAN_ASSETS%"=="false" ( + set CLEAN_ASSETS= +) +IF "%CLEAN_OUTPUT_DIRECTORY%"=="false" ( + set CLEAN_OUTPUT_DIRECTORY= +) + IF DEFINED CLEAN_ASSETS ( ECHO [ci_build] CLEAN_ASSETS option set FOR %%P in (%CMAKE_LY_PROJECTS%) do ( @@ -19,7 +29,26 @@ IF DEFINED CLEAN_ASSETS ( ECHO [ci_build] Deleting "%%P\Cache" DEL /s /q /f %%P\Cache 1>nul ) - ) + ) +) + +REM If the node label changes, we issue a clean output since node changes can change SDK/CMake/toolchains/etc +SET LAST_CONFIGURE_NODE_LABEL_FILE=ci_last_node_label.txt +IF DEFINED NODE_LABEL ( + IF EXIST %OUTPUT_DIRECTORY% ( + PUSHD %OUTPUT_DIRECTORY% + IF EXIST !LAST_CONFIGURE_NODE_LABEL_FILE! ( + FOR /F "delims=" %%x in (%LAST_CONFIGURE_NODE_LABEL_FILE%) DO SET LAST_NODE_LABEL=%%x + ) ELSE ( + SET LAST_NODE_LABEL= + ) + REM Detect if the node label has changed + IF !LAST_NODE_LABEL! NEQ !NODE_LABEL! ( + ECHO [ci_build] Last run was done with node label "!LAST_NODE_LABEL!", new node label is "!NODE_LABEL!", forcing CLEAN_OUTPUT_DIRECTORY + SET CLEAN_OUTPUT_DIRECTORY=1 + ) + POPD + ) ) IF DEFINED CLEAN_OUTPUT_DIRECTORY ( @@ -28,4 +57,12 @@ IF DEFINED CLEAN_OUTPUT_DIRECTORY ( ECHO [ci_build] Deleting "%OUTPUT_DIRECTORY%" DEL /s /q /f %OUTPUT_DIRECTORY% 1>nul ) -) \ No newline at end of file +) + +IF NOT EXIST "%OUTPUT_DIRECTORY%" ( + MKDIR %OUTPUT_DIRECTORY%. +) +REM Save the node label +PUSHD %OUTPUT_DIRECTORY% +ECHO !NODE_LABEL!> !LAST_CONFIGURE_NODE_LABEL_FILE! +POPD From 4405c2275fdc38e04d3d075eaf5e4c8a0a56ea86 Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 18:23:01 -0700 Subject: [PATCH 32/45] [default_3rdparty] changed CLI argument type to pathlib.Path and removed optional str type from usage --- scripts/o3de/o3de/register.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 2e37f04acf..4e73edca7f 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -521,7 +521,7 @@ def register_default_restricted_folder(json_data: dict, 'default_restricted_folder') def register_default_third_party_folder(json_data: dict, - default_third_party_folder: str or pathlib.Path, + default_third_party_folder: pathlib.Path, remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_third_party_folder() if remove else default_third_party_folder, @@ -539,7 +539,7 @@ def register(engine_path: str or pathlib.Path = None, default_gems_folder: str or pathlib.Path = None, default_templates_folder: str or pathlib.Path = None, default_restricted_folder: str or pathlib.Path = None, - default_third_party_folder: str or pathlib.Path = None, + default_third_party_folder: pathlib.Path = None, external_subdir_engine_path: pathlib.Path = None, external_subdir_project_path: pathlib.Path = None, remove: bool = False, @@ -628,7 +628,7 @@ def register(engine_path: str or pathlib.Path = None, elif isinstance(default_restricted_folder, str) or isinstance(default_restricted_folder, pathlib.PurePath): result = register_default_restricted_folder(json_data, default_restricted_folder, remove) - elif isinstance(default_third_party_folder, str) or isinstance(default_third_party_folder, pathlib.PurePath): + elif default_third_party_folder: result = register_default_third_party_folder(json_data, default_third_party_folder, remove) # engine is done LAST @@ -825,7 +825,7 @@ def add_parser_args(parser): help='The default templates folder to register/remove.') group.add_argument('-drf', '--default-restricted-folder', type=str, required=False, help='The default restricted folder to register/remove.') - group.add_argument('-dtpf', '--default-third-party-folder', type=str, required=False, + group.add_argument('-dtpf', '--default-third-party-folder', type=pathlib.Path, required=False, help='The default 3rd Party folder to register/remove.') group.add_argument('-u', '--update', action='store_true', required=False, default=False, From 9e7f8e45ebb073c3cb58bb2157d7368fb77f96d0 Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 18:23:54 -0700 Subject: [PATCH 33/45] [default_3rdparty] fixed typo --- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index ee4e30846b..37e636caef 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -421,7 +421,7 @@ namespace O3DE::ProjectManager pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString(); pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString(); pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString(); - pybind11::str defaultThridPartyFolder = engineInfo.m_thirdPartyPath.toStdString(); + pybind11::str defaultThirdPartyFolder = engineInfo.m_thirdPartyPath.toStdString(); auto registrationResult = m_register.attr("register")( enginePath, // engine_path @@ -436,7 +436,7 @@ namespace O3DE::ProjectManager defaultGemsFolder, defaultTemplatesFolder, pybind11::none(), // default_restricted_folder - defaultThridPartyFolder + defaultThirdPartyFolder ); if (registrationResult.cast() != 0) From fe98c34f5060ffe9053932eb0b71838d494787dc Mon Sep 17 00:00:00 2001 From: rhongAMZ <69218254+rhongAMZ@users.noreply.github.com> Date: Thu, 3 Jun 2021 19:59:29 -0700 Subject: [PATCH 34/45] EMFX - Refactor the emfx actor asset loading. (#1101) Refactor emfx asset loading. The mesh asset, skinMetaAsset and morphTargetMeta asset are part of the dependency. --- .../CommandSystem/Source/ImporterCommands.cpp | 5 +- .../RCExt/Actor/ActorGroupExporter.cpp | 52 +++-- .../Pipeline/RCExt/Actor/ActorGroupExporter.h | 3 + .../EMotionFX/Code/EMotionFX/Source/Actor.cpp | 183 ++++++------------ Gems/EMotionFX/Code/EMotionFX/Source/Actor.h | 43 ++-- .../Source/Integration/Assets/ActorAsset.cpp | 3 + .../Integration/Components/ActorComponent.cpp | 46 +---- .../Integration/Components/ActorComponent.h | 4 - .../Components/EditorActorComponent.cpp | 39 +--- .../Editor/Components/EditorActorComponent.h | 4 - 10 files changed, 137 insertions(+), 245 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp index ff05b603c0..08e1ddbb08 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp @@ -94,8 +94,9 @@ namespace CommandSystem return false; } - actor->LoadRemainingAssets(); - actor->CheckFinalizeActor(); + // Because the actor is directly loaded from disk (without going through an actor asset), we need to ask for a blocking + // load for the asset that actor is depend on. + actor->Finalize(EMotionFX::Actor::LoadRequirement::RequireBlockingLoad); // set the actor id in case we have specified it as parameter if (actorID != MCORE_INVALIDINDEX32) diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp index c7c6b86aea..d5f53e72c5 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp @@ -52,7 +52,7 @@ namespace EMotionFX AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - serializeContext->Class()->Version(1); + serializeContext->Class()->Version(2); } } @@ -117,21 +117,6 @@ namespace EMotionFX ExporterLib::SaveActor(filename, m_actor.get(), MCore::Endian::ENDIAN_LITTLE, GetMeshAssetId(context)); -#ifdef EMOTIONFX_ACTOR_DEBUG - // Use there line to create a log file and inspect detail debug info - AZStd::string folderPath; - AzFramework::StringFunc::Path::GetFolderPath(filename.c_str(), folderPath); - AZStd::string logFilename = folderPath; - logFilename += "EMotionFXExporter_Log.txt"; - MCore::GetLogManager().CreateLogFile(logFilename.c_str()); - EMotionFX::GetImporter().SetLogDetails(true); - filename += ".xac"; - - // use this line to load the actor from the saved actor file - EMotionFX::Actor* testLoadingActor = EMotionFX::GetImporter().LoadActor(AZStd::string(filename.c_str())); - MCore::Destroy(testLoadingActor); -#endif // EMOTIONFX_ACTOR_DEBUG - static AZ::Data::AssetType emotionFXActorAssetType("{F67CC648-EA51-464C-9F5D-4A9CE41A7F86}"); // from ActorAsset.h in EMotionFX Gem AZ::SceneAPI::Events::ExportProduct& product = context.m_products.AddProduct(AZStd::move(filename), context.m_group.GetId(), emotionFXActorAssetType, AZStd::nullopt, AZStd::nullopt); @@ -141,6 +126,26 @@ namespace EMotionFX product.m_legacyPathDependencies.emplace_back(AZStd::move(materialPathReference)); } + // Mesh asset, skin meta asset and morph target meta asset are sub assets for actor asset. + // In here we set them as the dependency of the actor asset. That make sure those assets get automatically loaded before actor asset. + // Default to the first product until we are able to establish a link between mesh and actor (ATOM-13590). + const AZ::Data::AssetType assetDependencyList[] = { + azrtti_typeid(), + azrtti_typeid(), + azrtti_typeid() + }; + + for (const AZ::Data::AssetType& assetDependency : assetDependencyList) + { + AZStd::optional result = GetFirstProductByType(context, assetDependency); + if (result != AZStd::nullopt) + { + AZ::SceneAPI::Events::ExportProduct exportProduct = result.value(); + exportProduct.m_dependencyFlags = AZ::Data::ProductDependencyInfo::CreateFlags(AZ::Data::AssetLoadBehavior::PreLoad); + product.m_productDependencies.emplace_back(exportProduct); + } + } + return SceneEvents::ProcessingResult::Success; } @@ -171,5 +176,20 @@ namespace EMotionFX return AZStd::nullopt; } + + AZStd::optional ActorGroupExporter::GetFirstProductByType( + const ActorGroupExportContext& context, AZ::Data::AssetType type) + { + const AZStd::vector& products = context.m_products.GetProducts(); + for (const AZ::SceneAPI::Events::ExportProduct& product : products) + { + if (product.m_assetType == type) + { + return product; + } + } + + return AZStd::nullopt; + } } // namespace Pipeline } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h index 451d1f4bb4..585126c07b 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -44,6 +45,8 @@ namespace EMotionFX //! Get the mesh asset id to which the actor is linked to by default. AZStd::optional GetMeshAssetId(const ActorGroupExportContext& context) const; + static AZStd::optional GetFirstProductByType( + const ActorGroupExportContext& context, AZ::Data::AssetType type); AutoRegisteredActor m_actor; AZStd::vector m_actorMaterialReferences; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp index 403e7ec05a..67f0773aec 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp @@ -125,7 +125,6 @@ namespace EMotionFX Actor::~Actor() { - AZ::Data::AssetBus::MultiHandler::BusDisconnect(); ActorNotificationBus::Broadcast(&ActorNotificationBus::Events::OnActorDestroyed, this); GetEventManager().OnDeleteActor(this); @@ -1463,108 +1462,78 @@ namespace EMotionFX return morphTargetMetaAssetInfo.m_assetId.IsValid(); } - void Actor::OnAssetReady(AZ::Data::Asset asset) - { - if (asset == m_meshAsset) - { - m_meshAsset = asset; - } - if (asset == m_skinMetaAsset) - { - m_skinMetaAsset = asset; - } - if (asset == m_morphTargetMetaAsset) - { - m_morphTargetMetaAsset = asset; - } - - CheckFinalizeActor(); - } - - void Actor::CheckFinalizeActor() + void Actor::Finalize(LoadRequirement loadReq) { AZStd::scoped_lock lock(m_mutex); - if (m_meshAsset.IsReady()) + // Load the mesh asset, skin meta asset and morph target asset. + // Those sub assets should have already been setup as dependency of actor asset, so they should already be loaded when we reach here. + // Only exception is that when the actor is not loaded by an actor asset, for which we need to do a blocking load. + if (m_meshAssetId.IsValid()) { - const AZ::Data::AssetId meshAssetId = m_meshAsset.GetId(); - const bool skinMetaAssetExists = DoesSkinMetaAssetExist(meshAssetId); - const bool morphTargetMetaAssetExists = DoesMorphTargetMetaAssetExist(m_meshAsset.GetId()); + // Get the mesh asset. + m_meshAsset = AZ::Data::AssetManager::Instance().GetAsset(m_meshAssetId, AZ::Data::AssetLoadBehavior::PreLoad); - m_skinToSkeletonIndexMap.clear(); - - // Skin and morph target meta assets are ready, fill the runtime mesh data. - if ((!skinMetaAssetExists || m_skinMetaAsset.IsReady()) && - (!morphTargetMetaAssetExists || m_morphTargetMetaAsset.IsReady())) + // Get the skin meta asset. + const AZ::Data::AssetId skinMetaAssetId = ConstructSkinMetaAssetId(m_meshAssetId); + if (DoesSkinMetaAssetExist(m_meshAssetId) && skinMetaAssetId.IsValid()) { - // Optional, not all actors have a skinned meshes. - if (skinMetaAssetExists) + m_skinMetaAsset = AZ::Data::AssetManager::Instance().GetAsset( + skinMetaAssetId, AZ::Data::AssetLoadBehavior::PreLoad); + } + + // Get the morph target meta asset. + const AZ::Data::AssetId morphTargetMetaAssetId = ConstructMorphTargetMetaAssetId(m_meshAssetId); + if (DoesMorphTargetMetaAssetExist(m_meshAssetId) && morphTargetMetaAssetId.IsValid()) + { + m_morphTargetMetaAsset = AZ::Data::AssetManager::Instance().GetAsset( + morphTargetMetaAssetId, AZ::Data::AssetLoadBehavior::PreLoad); + } + + if (loadReq == LoadRequirement::RequireBlockingLoad) + { + if (m_skinMetaAsset.IsLoading()) { - m_skinToSkeletonIndexMap = ConstructSkinToSkeletonIndexMap(m_skinMetaAsset); + m_skinMetaAsset.BlockUntilLoadComplete(); } - - ConstructMeshes(m_skinToSkeletonIndexMap); - - // Optional, not all actors have morph targets. - if (morphTargetMetaAssetExists) + if (m_morphTargetMetaAsset.IsLoading()) { - ConstructMorphTargets(); + m_morphTargetMetaAsset.BlockUntilLoadComplete(); } - else + if (m_meshAsset.IsLoading()) { - // Optional, not all actors have morph targets. - const size_t numLODLevels = m_meshAsset->GetLodAssets().size(); - mMorphSetups.Resize(numLODLevels); - for (AZ::u32 i = 0; i < numLODLevels; ++i) - { - mMorphSetups[i] = nullptr; - } + m_meshAsset.BlockUntilLoadComplete(); } - - SetActorReady(); - - // Do not release the mesh assets. We need the mesh data to initialize future instances of the render actor instances. - //m_meshAsset.Release(); - //m_skinMetaAsset.Release(); - //m_morphTargetMetaAsset.Release(); } } - } - void Actor::LoadRemainingAssets() - { - // Everything is ready already or no (skeleton-only) or an invalid mesh asset assigned. Emit ready signal directly. - if (m_isReady || !m_meshAssetId.IsValid()) + if (m_meshAsset.IsReady()) { - SetActorReady(); - return; + if (m_skinMetaAsset.IsReady()) + { + m_skinToSkeletonIndexMap = ConstructSkinToSkeletonIndexMap(m_skinMetaAsset); + } + ConstructMeshes(); + + if (m_morphTargetMetaAsset.IsReady()) + { + ConstructMorphTargets(); + } + else + { + // Optional, not all actors have morph targets. + const size_t numLODLevels = m_meshAsset->GetLodAssets().size(); + mMorphSetups.Resize(numLODLevels); + for (AZ::u32 i = 0; i < numLODLevels; ++i) + { + mMorphSetups[i] = nullptr; + } + } } - LoadMeshAssetsQueued(); - } - - void Actor::OnAssetReloaded(AZ::Data::Asset asset) - { - if (asset == m_meshAsset) - { - m_meshAsset = asset; - } - if (asset == m_skinMetaAsset) - { - m_skinMetaAsset = asset; - } - if (asset == m_morphTargetMetaAsset) - { - m_morphTargetMetaAsset = asset; - } - - CheckFinalizeActor(); - } - - void Actor::SetActorReady() - { m_isReady = true; ActorNotificationBus::Broadcast(&ActorNotificationBus::Events::OnActorReady, this); + // Do not release the mesh assets. We need the mesh data to initialize future instances of the render actor instances. } // update the static AABB (very heavy as it has to create an actor instance, update mesh deformers, calculate the mesh based bounds etc) @@ -2792,37 +2761,6 @@ namespace EMotionFX m_meshAssetId = assetId; } - void Actor::LoadMeshAssetsQueued() - { - AZStd::scoped_lock lock(m_mutex); - - // Mesh asset will be queue loaded on post init. - if (m_meshAssetId.IsValid()) - { - m_isReady = false; - AZ::Data::AssetBus::MultiHandler::BusDisconnect(); - - AZ::Data::AssetBus::MultiHandler::BusConnect(m_meshAssetId); - m_meshAsset = AZ::Data::AssetManager::Instance().GetAsset(m_meshAssetId, AZ::Data::AssetLoadBehavior::Default); - - // Skin meta asset - if (DoesSkinMetaAssetExist(m_meshAssetId)) - { - const AZ::Data::AssetId skinMetaAssetId = ConstructSkinMetaAssetId(m_meshAssetId); - AZ::Data::AssetBus::MultiHandler::BusConnect(skinMetaAssetId); - m_skinMetaAsset = AZ::Data::AssetManager::Instance().GetAsset(skinMetaAssetId, AZ::Data::AssetLoadBehavior::Default); - } - - // Morph target meta asset - if (DoesMorphTargetMetaAssetExist(m_meshAssetId)) - { - const AZ::Data::AssetId morphTargetMetaAssetId = ConstructMorphTargetMetaAssetId(m_meshAssetId); - AZ::Data::AssetBus::MultiHandler::BusConnect(morphTargetMetaAssetId); - m_morphTargetMetaAsset = AZ::Data::AssetManager::Instance().GetAsset(morphTargetMetaAssetId, AZ::Data::AssetLoadBehavior::Default); - } - } - } - Node* Actor::FindMeshJoint(const AZ::Data::Asset& lodModelAsset) const { const AZStd::array_view& sourceMeshes = lodModelAsset->GetMeshes(); @@ -2843,7 +2781,7 @@ namespace EMotionFX return mSkeleton->GetNode(0); } - void Actor::ConstructMeshes(const AZStd::unordered_map& skinToSkeletonIndexMap) + void Actor::ConstructMeshes() { AZ_Assert(m_meshAsset.IsReady(), "Mesh asset should be fully loaded and ready."); @@ -2855,7 +2793,8 @@ namespace EMotionFX SetNumLODLevels(numLODLevels, /*adjustMorphSetup=*/false); const uint32 numNodes = mSkeleton->GetNumNodes(); - // Remove all the materials and add them back based on the meshAsset. Eventually we will remove all the material from Actor and GLActor. + // Remove all the materials and add them back based on the meshAsset. Eventually we will remove all the material from Actor and + // GLActor. RemoveAllMaterials(); mMaterials.Resize(numLODLevels); @@ -2866,7 +2805,7 @@ namespace EMotionFX lodLevels[lodLevel].mNodeInfos.Resize(numNodes); // Create a single mesh for the actor. - Mesh* mesh = Mesh::CreateFromModelLod(lodAsset, skinToSkeletonIndexMap); + Mesh* mesh = Mesh::CreateFromModelLod(lodAsset, m_skinToSkeletonIndexMap); // Find an owning joint for the mesh. Node* meshJoint = FindMeshJoint(lodAsset); @@ -2896,13 +2835,14 @@ namespace EMotionFX continue; } - EMotionFX::SkinningInfoVertexAttributeLayer* skinLayer = static_cast(vertexAttributeLayer); + EMotionFX::SkinningInfoVertexAttributeLayer* skinLayer = + static_cast(vertexAttributeLayer); const AZ::u32 numOrgVerts = skinLayer->GetNumAttributes(); AZStd::set localJointIndices = skinLayer->CalcLocalJointIndices(numOrgVerts); const AZ::u32 numLocalJoints = static_cast(localJointIndices.size()); - // The information about if we want to use dual quat skinning is baked into the mesh chunk and we don't have access to that anymore. - // Default to dual quat skinning. + // The information about if we want to use dual quat skinning is baked into the mesh chunk and we don't have access to that + // anymore. Default to dual quat skinning. const bool dualQuatSkinning = true; if (dualQuatSkinning) { @@ -2970,7 +2910,8 @@ namespace EMotionFX void Actor::ConstructMorphTargets() { - AZ_Assert(m_meshAsset.IsReady() && m_morphTargetMetaAsset.IsReady(), "Mesh as well as morph target meta asset asset should be fully loaded and ready."); + AZ_Assert(m_meshAsset.IsReady() && m_morphTargetMetaAsset.IsReady(), + "Mesh as well as morph target meta asset asset should be fully loaded and ready."); AZStd::vector& lodLevels = m_meshLodData.m_lodLevels; const AZStd::array_view>& lodAssets = m_meshAsset->GetLodAssets(); const size_t numLODLevels = lodAssets.size(); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h index 9bf0daf046..3fe9711f18 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h @@ -63,7 +63,6 @@ namespace EMotionFX * still share the same data from the Actor class. The Actor contains information about the hierarchy/structure of the characters. */ class EMFX_API Actor - : private AZ::Data::AssetBus::MultiHandler { public: AZ_CLASS_ALLOCATOR_DECL @@ -101,6 +100,12 @@ namespace EMotionFX uint8 mFlags; // bitfield with MIRRORFLAG_ prefix }; + enum class LoadRequirement : bool + { + RequireBlockingLoad, + AllowAsyncLoad + }; + //------------------------------------------------ /** @@ -885,36 +890,35 @@ namespace EMotionFX bool GetOptimizeSkeleton() const { return m_optimizeSkeleton; } void SetMeshAssetId(const AZ::Data::AssetId& assetId); - void CheckFinalizeActor(); - void LoadMeshAssetsQueued(); - void LoadRemainingAssets(); + AZ::Data::AssetId GetMeshAssetId() const { return m_meshAssetId; }; const AZ::Data::Asset& GetMeshAsset() const { return m_meshAsset; } const AZ::Data::Asset& GetSkinMetaAsset() const { return m_skinMetaAsset; } const AZ::Data::Asset& GetMorphTargetMetaAsset() const { return m_morphTargetMetaAsset; } - const AZStd::unordered_map& GetSkinToSkeletonIndexMap() const { return m_skinToSkeletonIndexMap; } - void SetMeshAsset(AZ::Data::Asset asset) { m_meshAsset = asset; } - void SetSkinMetaAsset(AZ::Data::Asset asset) { m_skinMetaAsset = asset; } - void SetMorphTargetMetaAsset(AZ::Data::Asset asset) { m_morphTargetMetaAsset = asset; } + /** + * Is the actor fully ready? + * @result True in case the actor as well as its dependent files (e.g. mesh, skin, morph targets) are fully loaded and initialized. + **/ + bool IsReady() const { return m_isReady; } /** - * Is the actor fully ready? - * @result True in case the actor as well as its dependent files (e.g. mesh, skin, morph targets) are fully loaded and initialized. - **/ - bool IsReady() const { return m_isReady; } + * Finalize the actor with preload assets (mesh, skinmeta and morph target assets). + * LoadRequirement - We won't need a blocking load if the actor is part of the actor asset, as that will trigger the preload assets + * to load and get ready before finalize has been reached. + * However, if we are calling this on an actor that bypassed the asset system (e.g loading the actor directly from disk), it will require + * a blocking load. This option is now being used because emfx editor does not fully integrate with the asset system. + */ + void Finalize(LoadRequirement loadReq = LoadRequirement::AllowAsyncLoad); private: void InsertJointAndParents(AZ::u32 jointIndex, AZStd::unordered_set& includedJointIndices); - // AZ::Data::AssetBus::Handler - void OnAssetReady(AZ::Data::Asset asset) override; - void OnAssetReloaded(AZ::Data::Asset asset) override; - AZStd::unordered_map ConstructSkinToSkeletonIndexMap(const AZ::Data::Asset& skinMetaAsset); - void ConstructMeshes(const AZStd::unordered_map& skinToSkeletonIndexMap); + void ConstructMeshes(); void ConstructMorphTargets(); + Node* FindJointByMeshName(const AZStd::string_view meshName) const; // per node info (shared between lods) @@ -966,9 +970,6 @@ namespace EMotionFX Node* FindMeshJoint(const AZ::Data::Asset& lodModelAsset) const; - void SetActorReady(); - bool m_isReady = false; - Skeleton* mSkeleton; /**< The skeleton, containing the nodes and bind pose. */ MCore::Array mDependencies; /**< The dependencies on other actors (shared meshes and transforms). */ AZStd::vector mNodeInfos; /**< The per node info, shared between lods. */ @@ -992,7 +993,7 @@ namespace EMotionFX bool mDirtyFlag; /**< The dirty flag which indicates whether the user has made changes to the actor since the last file save operation. */ bool mUsedForVisualization; /**< Indicates if the actor is used for visualization specific things and is not used as a normal in-game actor. */ bool m_optimizeSkeleton; /**< Indicates if we should perform/ */ - + bool m_isReady = false; /**< If actor as well as its dependent files are fully loaded and initialized.*/ #if defined(EMFX_DEVELOPMENT_BUILD) bool mIsOwnedByRuntime; /**< Set if the actor is used/owned by the engine runtime. */ #endif // EMFX_DEVELOPMENT_BUILD diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp index 518db289e2..539b656754 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp @@ -68,6 +68,9 @@ namespace EMotionFX &actorSettings, ""); + assetData->m_emfxActor->Finalize(); + + // Clear out the EMFX raw asset data. assetData->ReleaseEMotionFXData(); if (!assetData->m_emfxActor) diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp index 982b62fbcf..f41ef165c8 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp @@ -154,17 +154,15 @@ namespace EMotionFX Actor* actor = m_configuration.m_actorAsset->GetActor(); if (actor) { - OnActorReady(actor); + CheckActorCreation(); } } ////////////////////////////////////////////////////////////////////////// ActorComponent::ActorComponent(const Configuration* configuration) : m_debugDrawRoot(false) - , m_sceneFinishSimHandler([this]( - [[maybe_unused]] AzPhysics::SceneHandle sceneHandle, - float fixedDeltatime - ) + , m_sceneFinishSimHandler([this]([[maybe_unused]] AzPhysics::SceneHandle sceneHandle, + float fixedDeltatime) { if (m_actorInstance) { @@ -192,18 +190,9 @@ namespace EMotionFX if (cfg.m_actorAsset.GetId().IsValid()) { - EMotionFX::ActorNotificationBus::Handler::BusDisconnect(); AZ::Data::AssetBus::Handler::BusDisconnect(); - EMotionFX::ActorNotificationBus::Handler::BusConnect(); AZ::Data::AssetBus::Handler::BusConnect(cfg.m_actorAsset.GetId()); cfg.m_actorAsset.QueueLoad(); - - // In case the asset was already loaded fully, create the actor directly. - if (cfg.m_actorAsset.IsReady() && - cfg.m_actorAsset->GetActor()) - { - cfg.m_actorAsset->GetActor()->LoadRemainingAssets(); - } } AZ::TickBus::Handler::BusConnect(); @@ -231,7 +220,6 @@ namespace EMotionFX LmbrCentral::AttachmentComponentNotificationBus::Handler::BusDisconnect(); AZ::TransformNotificationBus::MultiHandler::BusDisconnect(); AZ::Data::AssetBus::Handler::BusDisconnect(); - EMotionFX::ActorNotificationBus::Handler::BusDisconnect(); DestroyActor(); m_configuration.m_actorAsset.Release(); @@ -314,28 +302,12 @@ namespace EMotionFX Actor* actor = m_configuration.m_actorAsset->GetActor(); AZ_Assert(m_configuration.m_actorAsset.IsReady() && actor, "Actor asset should be loaded and actor valid."); - actor->LoadRemainingAssets(); - actor->CheckFinalizeActor(); + CheckActorCreation(); } void ActorComponent::OnAssetReloaded(AZ::Data::Asset asset) { - DestroyActor(); - m_configuration.m_actorAsset = asset; - - const Actor* oldActor = m_configuration.m_actorAsset->GetActor(); - AZ::Data::Asset meshAsset = oldActor->GetMeshAsset(); - AZ::Data::Asset skinMetaAsset = oldActor->GetSkinMetaAsset(); - AZ::Data::Asset morphTargetMetaAsset = oldActor->GetMorphTargetMetaAsset(); - - m_configuration.m_actorAsset = asset; - Actor* newActor = m_configuration.m_actorAsset->GetActor(); - AZ_Assert(m_configuration.m_actorAsset.IsReady() && newActor, "Actor asset should be loaded and actor valid."); - - newActor->SetMeshAsset(meshAsset); - newActor->SetSkinMetaAsset(skinMetaAsset); - newActor->SetMorphTargetMetaAsset(morphTargetMetaAsset); - newActor->CheckFinalizeActor(); + OnAssetReady(asset); } bool ActorComponent::IsPhysicsSceneSimulationFinishEventConnected() const @@ -850,13 +822,5 @@ namespace EMotionFX m_actorInstance->RemoveAttachment(targetActorInstance); } } - - void ActorComponent::OnActorReady(Actor* actor) - { - if (m_configuration.m_actorAsset && m_configuration.m_actorAsset->GetActor() == actor) - { - CheckActorCreation(); - } - } } // namespace Integration } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h index 8188da19b4..4172ce63bc 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h @@ -44,7 +44,6 @@ namespace EMotionFX , private LmbrCentral::AttachmentComponentNotificationBus::Handler , private AzFramework::CharacterPhysicsDataRequestBus::Handler , private AzFramework::RagdollPhysicsNotificationBus::Handler - , private EMotionFX::ActorNotificationBus::Handler { public: AZ_COMPONENT(ActorComponent, "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}"); @@ -168,9 +167,6 @@ namespace EMotionFX void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; int GetTickOrder() override; - // ActorNotificationBus::Handler - void OnActorReady(Actor* actor) override; - void CheckActorCreation(); void DestroyActor(); void CheckAttachToEntity(); diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp index d22bb0007f..7d5b7ade00 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp @@ -156,8 +156,6 @@ namespace EMotionFX ////////////////////////////////////////////////////////////////////////// void EditorActorComponent::Activate() { - EMotionFX::ActorNotificationBus::Handler::BusConnect(); - LoadActorAsset(); const AZ::EntityId entityId = GetEntityId(); @@ -186,8 +184,6 @@ namespace EMotionFX AZ::TickBus::Handler::BusDisconnect(); AZ::Data::AssetBus::Handler::BusDisconnect(); - EMotionFX::ActorNotificationBus::Handler::BusDisconnect(); - DestroyActorInstance(); m_actorAsset.Release(); } @@ -234,13 +230,6 @@ namespace EMotionFX AZ::Data::AssetBus::Handler::BusDisconnect(); AZ::Data::AssetBus::Handler::BusConnect(m_actorAsset.GetId()); m_actorAsset.QueueLoad(); - - // In case the asset was already loaded fully, create the actor directly. - if (m_actorAsset.IsReady() && - m_actorAsset->GetActor()) - { - m_actorAsset->GetActor()->LoadRemainingAssets(); - } } else { @@ -475,27 +464,13 @@ namespace EMotionFX Actor* actor = m_actorAsset->GetActor(); AZ_Assert(m_actorAsset.IsReady() && actor, "Actor asset should be loaded and actor valid."); - actor->LoadRemainingAssets(); - actor->CheckFinalizeActor(); + CheckActorCreation(); } void EditorActorComponent::OnAssetReloaded(AZ::Data::Asset asset) { DestroyActorInstance(); - - const Actor* oldActor = m_actorAsset->GetActor(); - AZ::Data::Asset meshAsset = oldActor->GetMeshAsset(); - AZ::Data::Asset skinMetaAsset = oldActor->GetSkinMetaAsset(); - AZ::Data::Asset morphTargetMetaAsset = oldActor->GetMorphTargetMetaAsset(); - - m_actorAsset = asset; - Actor* newActor = m_actorAsset->GetActor(); - AZ_Assert(m_actorAsset.IsReady() && newActor, "Actor asset should be loaded and actor valid."); - - newActor->SetMeshAsset(meshAsset); - newActor->SetSkinMetaAsset(skinMetaAsset); - newActor->SetMorphTargetMetaAsset(morphTargetMetaAsset); - newActor->CheckFinalizeActor(); + OnAssetReady(asset); } void EditorActorComponent::SetActorAsset(AZ::Data::Asset actorAsset) @@ -505,7 +480,7 @@ namespace EMotionFX Actor* actor = m_actorAsset->GetActor(); if (actor) { - OnActorReady(actor); + CheckActorCreation(); } } @@ -818,14 +793,6 @@ namespace EMotionFX return false; } - void EditorActorComponent::OnActorReady(Actor* actor) - { - if (m_actorAsset && m_actorAsset->GetActor() == actor) - { - CheckActorCreation(); - } - } - void EditorActorComponent::CheckActorCreation() { // Enable/disable debug drawing. diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h index 8ddd95c3b7..5dabbe4ada 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h @@ -45,7 +45,6 @@ namespace EMotionFX , private AzToolsFramework::EditorComponentSelectionRequestsBus::Handler , private AzToolsFramework::EditorVisibilityNotificationBus::Handler , public AzFramework::BoundsRequestBus::Handler - , private EMotionFX::ActorNotificationBus::Handler { public: AZ_EDITOR_COMPONENT(EditorActorComponent, "{A863EE1B-8CFD-4EDD-BA0D-1CEC2879AD44}"); @@ -142,9 +141,6 @@ namespace EMotionFX void OnAttached(AZ::EntityId targetId) override; void OnDetached(AZ::EntityId targetId) override; - // ActorNotificationBus::Handler - void OnActorReady(Actor* actor) override; - void CheckActorCreation(); void BuildGameEntity(AZ::Entity* gameEntity) override; From f39460e617d56358c83c8227203b83f547d386e5 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 3 Jun 2021 20:08:51 -0700 Subject: [PATCH 35/45] Fix rare re-entrancy issue with CCryEditApp::IdleProcessing (#1134) This issue manifested in a crash in rare circumstances when the Editor lost and gained focus while a modal dialog was active. After investigation, it was discovered that native event processing can lead to IdleProcessing being called again from the main thread while idle processing is still happening. As this is unintentional and generally undesirable, we now guard against this within the IdleProcessing method. --- Code/Sandbox/Editor/CryEdit.cpp | 8 ++++++++ Code/Sandbox/Editor/CryEdit.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/Code/Sandbox/Editor/CryEdit.cpp b/Code/Sandbox/Editor/CryEdit.cpp index c723e6049a..a972a4bd9b 100644 --- a/Code/Sandbox/Editor/CryEdit.cpp +++ b/Code/Sandbox/Editor/CryEdit.cpp @@ -2281,6 +2281,14 @@ int CCryEditApp::IdleProcessing(bool bBackgroundUpdate) return 0; } + // Ensure we don't get called re-entrantly + // This can occur when a nested Qt event loop fires (e.g. by way of a modal dialog calling exec) + if (m_idleProcessingRunning) + { + return 0; + } + QScopedValueRollback guard(m_idleProcessingRunning, true); + //////////////////////////////////////////////////////////////////////// // Call the update function of the engine //////////////////////////////////////////////////////////////////////// diff --git a/Code/Sandbox/Editor/CryEdit.h b/Code/Sandbox/Editor/CryEdit.h index dc4f015faf..e37fb53561 100644 --- a/Code/Sandbox/Editor/CryEdit.h +++ b/Code/Sandbox/Editor/CryEdit.h @@ -335,6 +335,8 @@ private: // If this flag is set, the next OnIdle() will update, even if the app is in the background, and then // this flag will be reset. bool m_bForceProcessIdle = false; + // This is set while IdleProcessing is running to prevent re-entrancy + bool m_idleProcessingRunning = false; // Keep the editor alive, even if no focus is set bool m_bKeepEditorActive = false; // Currently creating a new level From 34449e2fc9085e2cf5d3a7e2836479f4977d65b7 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 3 Jun 2021 20:09:04 -0700 Subject: [PATCH 36/45] Guard GridComponent against arbitrarily high grid sizes (#1135) Also do bounds checking at runtime in the controller for safety. --- .../Code/Source/Grid/EditorGridComponent.cpp | 7 ++++--- .../Code/Source/Grid/GridComponentController.cpp | 6 +++--- .../Code/Source/Grid/GridComponentController.h | 4 ++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp index f500bdd6e2..81fc3aa170 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp @@ -54,13 +54,14 @@ namespace AZ ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &GridComponentConfig::m_gridSize, "Grid Size", "Grid width and depth") - ->Attribute(AZ::Edit::Attributes::Min, 0.0f) + ->Attribute(AZ::Edit::Attributes::Min, GridComponentController::MinGridSize) + ->Attribute(AZ::Edit::Attributes::Max, GridComponentController::MaxGridSize) ->Attribute(AZ::Edit::Attributes::Suffix, " m") ->DataElement(AZ::Edit::UIHandlers::Default, &GridComponentConfig::m_primarySpacing, "Primary Grid Spacing", "Amount of space between grid lines") - ->Attribute(AZ::Edit::Attributes::Min, 0.01f) + ->Attribute(AZ::Edit::Attributes::Min, GridComponentController::MinSpacing) ->Attribute(AZ::Edit::Attributes::Suffix, " m") ->DataElement(AZ::Edit::UIHandlers::Default, &GridComponentConfig::m_secondarySpacing, "Secondary Grid Spacing", "Amount of space between sub-grid lines") - ->Attribute(AZ::Edit::Attributes::Min, 0.01f) + ->Attribute(AZ::Edit::Attributes::Min, GridComponentController::MinSpacing) ->Attribute(AZ::Edit::Attributes::Suffix, " m") ->DataElement(AZ::Edit::UIHandlers::Color, &GridComponentConfig::m_axisColor, "Axis Color", "Color of the grid axis") ->DataElement(AZ::Edit::UIHandlers::Color, &GridComponentConfig::m_primaryColor, "Primary Color", "Color of the primary grid lines") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp index c2f9c896af..279c8d9035 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp @@ -115,7 +115,7 @@ namespace AZ void GridComponentController::SetSize(float gridSize) { - m_configuration.m_gridSize = gridSize; + m_configuration.m_gridSize = AZStd::clamp(gridSize, MinGridSize, MaxGridSize); m_dirty = true; } @@ -126,7 +126,7 @@ namespace AZ void GridComponentController::SetPrimarySpacing(float gridPrimarySpacing) { - m_configuration.m_primarySpacing = gridPrimarySpacing; + m_configuration.m_primarySpacing = AZStd::max(gridPrimarySpacing, MinSpacing); m_dirty = true; } @@ -137,7 +137,7 @@ namespace AZ void GridComponentController::SetSecondarySpacing(float gridSecondarySpacing) { - m_configuration.m_secondarySpacing = gridSecondarySpacing; + m_configuration.m_secondarySpacing = AZStd::max(gridSecondarySpacing, MinSpacing); m_dirty = true; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.h index afba6d8327..ad603f11e1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.h @@ -46,6 +46,10 @@ namespace AZ void SetConfiguration(const GridComponentConfig& config); const GridComponentConfig& GetConfiguration() const; + static constexpr float MinGridSize = 0.0f; + static constexpr float MaxGridSize = 1000000.0f; + static constexpr float MinSpacing = 0.01f; + private: AZ_DISABLE_COPY(GridComponentController); From 30eedc1c554c8ae01e5be9d22cc372d757cd7bd0 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 3 Jun 2021 20:09:15 -0700 Subject: [PATCH 37/45] Avoid more sources of camera update re-entrancy that can lead to stack overflow (#1136) --- Code/Sandbox/Editor/EditorViewportWidget.cpp | 3 +++ Gems/Camera/Code/Source/CameraComponentController.cpp | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index 667179e3cd..0d3405f8f0 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -2887,9 +2887,12 @@ void EditorViewportWidget::UpdateCameraFromViewportContext() AZ::Matrix3x4 matrix; matrix.SetBasisAndTranslation(cameraState.m_side, cameraState.m_forward, cameraState.m_up, cameraState.m_position); auto m = AZMatrix3x4ToLYMatrix3x4(matrix); + + m_updatingCameraPosition = true; SetViewTM(m); SetFOV(cameraState.m_fovOrZoom); m_Camera.SetZRange(cameraState.m_nearClip, cameraState.m_farClip); + m_updatingCameraPosition = false; } void EditorViewportWidget::SetAsActiveViewport() diff --git a/Gems/Camera/Code/Source/CameraComponentController.cpp b/Gems/Camera/Code/Source/CameraComponentController.cpp index cad666c1cd..78bd131002 100644 --- a/Gems/Camera/Code/Source/CameraComponentController.cpp +++ b/Gems/Camera/Code/Source/CameraComponentController.cpp @@ -387,6 +387,11 @@ namespace Camera void CameraComponentController::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world) { + if (m_updatingTransformFromEntity) + { + return; + } + if (m_view) { CCamera& camera = m_view->GetCamera(); From 4a1d713227af339b2fbb86eb02c936cc079863c5 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 3 Jun 2021 22:36:34 -0500 Subject: [PATCH 38/45] Fix recursive attempts to open the log file in the GameLauncher (#1114) * Fix recursive attempts to open the log file in the GameLauncher The AzFramework Application has been updated to default the @user@ and @log@ aliases to the /user and /user/log folder respectively if a project isn't set. Fixed the SystemFile class to support negative offsets if Seek() as per standard seek function such as fseek Updated the CrySystem CLog class to use SystemFile instead of FileIOBase to avoid any asserts that would cause CLog::OpenFile to be recursively called infinitely * Removing unused Force Closed variable * AZ::IO::SystemFile build fixes for Unix platforms. Added a copy constructor for LUAEditorContextInterface.h to fix the LuaEditor build * Adding missing includes to the WindowsAPI and Android SystemFile headers --- Code/CryEngine/CrySystem/Log.cpp | 106 +++++++++--------- Code/CryEngine/CrySystem/Log.h | 18 ++- Code/CryEngine/CrySystem/SystemInit.cpp | 2 +- .../Framework/AzCore/AzCore/IO/SystemFile.cpp | 60 ++++++---- Code/Framework/AzCore/AzCore/IO/SystemFile.h | 21 ++-- .../Settings/SettingsRegistryMergeUtils.cpp | 2 + .../Android/AzCore/IO/SystemFile_Android.cpp | 10 +- .../Android/AzCore/IO/SystemFile_Android.h | 6 +- .../Common/Apple/AzCore/IO/SystemFile_Apple.h | 5 +- .../UnixLike/AzCore/IO/SystemFile_UnixLike.h | 6 +- .../AzCore/IO/SystemFile_UnixLikeDefault.cpp | 6 +- .../WinAPI/AzCore/IO/SystemFile_WinAPI.cpp | 8 +- .../WinAPI/AzCore/IO/SystemFile_WinAPI.h | 6 +- .../AzFramework/Application/Application.cpp | 13 ++- .../Source/LUA/LUAEditorContextInterface.h | 46 ++++++++ 15 files changed, 200 insertions(+), 115 deletions(-) diff --git a/Code/CryEngine/CrySystem/Log.cpp b/Code/CryEngine/CrySystem/Log.cpp index b8241ee865..af5170e4e5 100644 --- a/Code/CryEngine/CrySystem/Log.cpp +++ b/Code/CryEngine/CrySystem/Log.cpp @@ -26,6 +26,7 @@ #include #include +#include #ifdef WIN32 #include @@ -88,7 +89,6 @@ CLog::CLog(ISystem* pSystem) m_nMainThreadId = CryGetCurrentThreadId(); - m_logFileHandle = AZ::IO::InvalidHandle; #if defined(KEEP_LOG_FILE_OPEN) m_bFirstLine = true; #endif @@ -162,35 +162,6 @@ void CLog::RegisterConsoleVariables() REGISTER_COMMAND("log_flush", &LogFlushFile, 0, "Flush the log file"); #endif } - /* - //testbed - { - int iSave0 = m_pLogVerbosity->GetIVal(); - int iSave1 = m_pLogFileVerbosity->GetIVal(); - - for(int i=0;i<=4;++i) - { - m_pLogVerbosity->Set(i); - m_pLogFileVerbosity->Set(i); - - LogWithType(eAlways,"CLog selftest: Verbosity=%d FileVerbosity=%d",m_pLogVerbosity->GetIVal(),m_pLogFileVerbosity->GetIVal()); - LogWithType(eAlways,"--------------"); - - LogWithType(eError,"eError"); - LogWithType(eWarning,"eWarning"); - LogWithType(eMessage,"eMessage"); - LogWithType(eInput,"eInput"); - LogWithType(eInputResponse,"eInputResponse"); - - LogWarning("LogWarning()"); - LogError("LogError()"); - LogWithType(eAlways,"--------------"); - } - - m_pLogVerbosity->Set(iSave0); - m_pLogFileVerbosity->Set(iSave1); - } - */ #undef DEFAULT_VERBOSITY } @@ -210,7 +181,7 @@ CLog::~CLog() UnregisterConsoleVariables(); - CloseLogFile(true); + CloseLogFile(); } void CLog::UnregisterConsoleVariables() @@ -224,31 +195,36 @@ void CLog::UnregisterConsoleVariables() } ////////////////////////////////////////////////////////////////////////// -void CLog::CloseLogFile([[maybe_unused]] bool forceClose) +void CLog::CloseLogFile() { - if (m_logFileHandle != AZ::IO::InvalidHandle) - { - AZ::IO::FileIOBase::GetDirectInstance()->Close(m_logFileHandle); - m_logFileHandle = AZ::IO::InvalidHandle; - } + m_logFileHandle.Close(); } ////////////////////////////////////////////////////////////////////////// -AZ::IO::HandleType CLog::OpenLogFile(const char* filename, const char* mode) +bool CLog::OpenLogFile(const char* filename, int mode) { - using namespace AZ::IO; - - AZ_Assert(m_logFileHandle == AZ::IO::InvalidHandle, "Attempt to open log file when one is already open. This would lead to a handle leak."); - - if ((!filename) || (filename[0] == 0)) + if (m_logFileHandle.IsOpen()) { - return m_logFileHandle; + // Can only AZ_Assert if a file is open, otherwise the AZ_Assert + // would eventually lead to OpenLogFile being opened up again + AZ_Assert(false, "Attempt to open log file when one is already open. This would lead to a handle leak."); + return false; + } + + if (filename == nullptr || filename[0] == '\0') + { + return false; } // it is assumed that @log@ points at the appropriate place (so for apple, to the user profile dir) - AZ::IO::FileIOBase::GetDirectInstance()->Open(filename, AZ::IO::GetOpenModeFromStringMode(mode), m_logFileHandle); + AZ::IO::FileIOBase* fileSystem = AZ::IO::FileIOBase::GetDirectInstance(); + if (AZ::IO::FixedMaxPath logFilePath; fileSystem->ReplaceAlias(logFilePath, filename)) + { + logFilePath = logFilePath.LexicallyNormal(); + m_logFileHandle.Open(logFilePath.c_str(), mode); + } - if (m_logFileHandle != AZ::IO::InvalidHandle) + if (m_logFileHandle.IsOpen()) { #if defined(KEEP_LOG_FILE_OPEN) m_bFirstLine = true; @@ -257,11 +233,11 @@ AZ::IO::HandleType CLog::OpenLogFile(const char* filename, const char* mode) else { #if defined(LINUX) || defined(APPLE) - syslog(LOG_NOTICE, "Failed to open log file [%s], mode [%s]", filename, mode); + syslog(LOG_NOTICE, "Failed to open log file [%s], mode [%d]", filename, mode); #endif } - return m_logFileHandle; + return m_logFileHandle.IsOpen(); } ////////////////////////////////////////////////////////////////////////// @@ -1114,12 +1090,15 @@ void CLog::LogStringToFile(const char* szString, ELogType logType, bool bAdd, [[ if (logToFile) { - if (m_logFileHandle == AZ::IO::InvalidHandle) + if (!m_logFileHandle.IsOpen()) { - OpenLogFile(m_szFilename, "w+t"); + constexpr auto openMode = AZ::IO::SystemFile::OpenMode::SF_OPEN_APPEND + | AZ::IO::SystemFile::OpenMode::SF_OPEN_CREATE + | AZ::IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY; + OpenLogFile(m_szFilename, openMode); } - if (m_logFileHandle != AZ::IO::InvalidHandle) + if (m_logFileHandle.IsOpen()) { #if defined(KEEP_LOG_FILE_OPEN) if (m_bFirstLine) @@ -1130,9 +1109,9 @@ void CLog::LogStringToFile(const char* szString, ELogType logType, bool bAdd, [[ if (bAdd) { // if adding to a prior line erase the \n at the end. - AZ::IO::FileIOBase::GetDirectInstance()->Seek(m_logFileHandle, -2, AZ::IO::SeekType::SeekFromEnd); + m_logFileHandle.Seek(-2, AZ::IO::SystemFile::SeekMode::SF_SEEK_END); } - AZ::IO::FPutS(tempString.c_str(), m_logFileHandle); + m_logFileHandle.Write(tempString.c_str(), tempString.size()); #if !defined(KEEP_LOG_FILE_OPEN) CloseLogFile(); #endif @@ -1383,6 +1362,23 @@ bool CLog::SetFileName(const char* fileNameOrAbsolutePath, bool backupLogs) CreateBackupFile(); + AZ::IO::FileIOBase* fileSystem = AZ::IO::FileIOBase::GetDirectInstance(); + AZ::IO::FixedMaxPath newLogFilePath; + if (fileSystem->ReplaceAlias(newLogFilePath, m_szFilename)) + { + newLogFilePath = newLogFilePath.LexicallyNormal(); + } + if (m_logFileHandle.IsOpen() && newLogFilePath != m_logFileHandle.Name()) + { + constexpr auto openMode = AZ::IO::SystemFile::OpenMode::SF_OPEN_APPEND + | AZ::IO::SystemFile::OpenMode::SF_OPEN_CREATE + | AZ::IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY; + if(AZ::IO::SystemFile newLogFile; newLogFile.Open(m_szFilename, openMode)) + { + m_logFileHandle = AZStd::move(newLogFile); + } + } + return true; } @@ -1537,9 +1533,9 @@ const char* CLog::GetModuleFilter() void CLog::FlushAndClose() { #if defined(KEEP_LOG_FILE_OPEN) - if (m_logFileHandle) + if (m_logFileHandle.IsOpen()) { - CloseLogFile(true); + CloseLogFile(); } #endif } diff --git a/Code/CryEngine/CrySystem/Log.h b/Code/CryEngine/CrySystem/Log.h index 911043871a..e19c2d19da 100644 --- a/Code/CryEngine/CrySystem/Log.h +++ b/Code/CryEngine/CrySystem/Log.h @@ -137,8 +137,8 @@ private: // ------------------------------------------------------------------- void LogStringToConsole(const char* szString, ELogType logType, bool bAdd) {} #endif // !defined(EXCLUDE_NORMAL_LOG) - AZ::IO::HandleType OpenLogFile(const char* filename, const char* mode); - void CloseLogFile(bool force = false); + bool OpenLogFile(const char* filename, int mode); + void CloseLogFile(); // will format the message into m_szTemp void FormatMessage(const char* szCommand, ...) PRINTF_PARAMS(2, 3); @@ -152,15 +152,11 @@ private: // ------------------------------------------------------------------- virtual const char* GetAssetScopeString(); #endif - ISystem* m_pSystem; // - float m_fLastLoadingUpdateTime; // for non-frequent streamingEngine update - //char m_szTemp[MAX_TEMP_LENGTH_SIZE]; // - char m_szFilename[MAX_FILENAME_SIZE]; // can be with path - mutable char m_sBackupFilename[MAX_FILENAME_SIZE]; // can be with path - AZ::IO::HandleType m_logFileHandle; - CryStackStringT m_LogMode; //mode m_pLogFile has been opened with - AZ::IO::HandleType m_errFileHandle; - int m_nErrCount; + ISystem* m_pSystem; // + float m_fLastLoadingUpdateTime; // for non-frequent streamingEngine update + char m_szFilename[MAX_FILENAME_SIZE]; // can be with path + mutable char m_sBackupFilename[MAX_FILENAME_SIZE]; // can be with path + AZ::IO::SystemFile m_logFileHandle; bool m_backupLogs; diff --git a/Code/CryEngine/CrySystem/SystemInit.cpp b/Code/CryEngine/CrySystem/SystemInit.cpp index 4a4296bbb5..97a3bbbe54 100644 --- a/Code/CryEngine/CrySystem/SystemInit.cpp +++ b/Code/CryEngine/CrySystem/SystemInit.cpp @@ -1208,7 +1208,7 @@ bool CSystem::Init(const SSystemInitParams& startupParams) { assetPlatform = AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, R"(A valid asset platform is missing in "%s/assets" key in the SettingsRegistry.)""\n" - R"(This typically done by setting he "assets" field in the bootstrap.cfg for within a .setreg file)""\n" + R"(This typically done by setting the "assets" field within a .setreg file)""\n" R"(A fallback of %s will be used.)", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, assetPlatform.c_str()); diff --git a/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp b/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp index 7c535d4aaf..6887d22ba7 100644 --- a/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp +++ b/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp @@ -30,7 +30,7 @@ namespace Platform using FileHandleType = SystemFile::FileHandleType; - void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode); + void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode); SystemFile::SizeType Tell(FileHandleType handle, const SystemFile* systemFile); bool Eof(FileHandleType handle, const SystemFile* systemFile); AZ::u64 ModificationTime(FileHandleType handle, const SystemFile* systemFile); @@ -68,9 +68,8 @@ void SystemFile::CreatePath(const char* fileName) } SystemFile::SystemFile() + : m_handle{ AZ_TRAIT_SYSTEMFILE_INVALID_HANDLE } { - m_fileName[0] = '\0'; - m_handle = AZ_TRAIT_SYSTEMFILE_INVALID_HANDLE; } SystemFile::~SystemFile() @@ -81,6 +80,25 @@ SystemFile::~SystemFile() } } +SystemFile::SystemFile(SystemFile&& other) + : SystemFile{} +{ + AZStd::swap(m_fileName, other.m_fileName); + AZStd::swap(m_handle, other.m_handle); +} + +SystemFile& SystemFile::operator=(SystemFile&& other) +{ + // Close the current file and take over the SystemFile handle and filename + Close(); + m_fileName = AZStd::move(other.m_fileName); + m_handle = AZStd::move(other.m_handle); + other.m_fileName = {}; + other.m_handle = AZ_TRAIT_SYSTEMFILE_INVALID_HANDLE; + + return *this; +} + bool SystemFile::Open(const char* fileName, int mode, int platformFlags) { AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Open - %s", fileName); @@ -88,42 +106,42 @@ bool SystemFile::Open(const char* fileName, int mode, int platformFlags) if (fileName) // If we reopen the file we are allowed to have NULL file name { - if (strlen(fileName) > AZ_ARRAY_SIZE(m_fileName) - 1) + if (strlen(fileName) > m_fileName.max_size()) { EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, 0); return false; } // store the filename - azsnprintf(m_fileName, AZ_ARRAY_SIZE(m_fileName), "%s", fileName); + m_fileName = fileName; } if (FileIOBus::HasHandlers()) { bool isOpen = false; bool isHandled = false; - EBUS_EVENT_RESULT(isHandled, FileIOBus, OnOpen, *this, m_fileName, mode, platformFlags, isOpen); + EBUS_EVENT_RESULT(isHandled, FileIOBus, OnOpen, *this, m_fileName.c_str(), mode, platformFlags, isOpen); if (isHandled) { return isOpen; } } - AZ_Assert(!IsOpen(), "This file (%s) is already open!", m_fileName); + AZ_Assert(!IsOpen(), "This file (%s) is already open!", m_fileName.c_str()); return PlatformOpen(mode, platformFlags); } bool SystemFile::ReOpen(int mode, int platformFlags) { - AZ_Assert(strlen(m_fileName) > 0, "Missing filename. You must call open first!"); + AZ_Assert(!m_fileName.empty(), "Missing filename. You must call open first!"); return Open(0, mode, platformFlags); } void SystemFile::Close() { - AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Close - %s", m_fileName); - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Close - %s", m_fileName); + AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Close - %s", m_fileName.c_str()); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Close - %s", m_fileName.c_str()); if (FileIOBus::HasHandlers()) { @@ -138,9 +156,9 @@ void SystemFile::Close() PlatformClose(); } -void SystemFile::Seek(SizeType offset, SeekMode mode) +void SystemFile::Seek(SeekSizeType offset, SeekMode mode) { - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Seek - %s:%i", m_fileName, offset); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Seek - %s:%i", m_fileName.c_str(), offset); if (FileIOBus::HasHandlers()) { @@ -167,15 +185,15 @@ bool SystemFile::Eof() AZ::u64 SystemFile::ModificationTime() { - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::ModTime - %s", m_fileName); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::ModTime - %s", m_fileName.c_str()); return Platform::ModificationTime(m_handle, this); } SystemFile::SizeType SystemFile::Read(SizeType byteSize, void* buffer) { - AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Read - %s:%i", m_fileName, byteSize); - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Read - %s:%i", m_fileName, byteSize); + AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Read - %s:%i", m_fileName.c_str(), byteSize); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Read - %s:%i", m_fileName.c_str(), byteSize); if (FileIOBus::HasHandlers()) { @@ -193,8 +211,8 @@ SystemFile::SizeType SystemFile::Read(SizeType byteSize, void* buffer) SystemFile::SizeType SystemFile::Write(const void* buffer, SizeType byteSize) { - AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Write - %s:%i", m_fileName, byteSize); - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Write - %s:%i", m_fileName, byteSize); + AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Write - %s:%i", m_fileName.c_str(), byteSize); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Write - %s:%i", m_fileName.c_str(), byteSize); if (FileIOBus::HasHandlers()) { @@ -212,14 +230,14 @@ SystemFile::SizeType SystemFile::Write(const void* buffer, SizeType byteSize) void SystemFile::Flush() { - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Flush - %s", m_fileName); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Flush - %s", m_fileName.c_str()); Platform::Flush(m_handle, this); } SystemFile::SizeType SystemFile::Length() const { - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Length - %s", m_fileName); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Length - %s", m_fileName.c_str()); return Platform::Length(m_handle, this); } @@ -379,9 +397,9 @@ namespace HasPosixEnumOption(PermissionModeFlags::Write); #undef HasPosixEnumOption -} +} + - FileDescriptorRedirector::FileDescriptorRedirector(int sourceFileDescriptor) : m_sourceFileDescriptor(sourceFileDescriptor) { diff --git a/Code/Framework/AzCore/AzCore/IO/SystemFile.h b/Code/Framework/AzCore/AzCore/IO/SystemFile.h index 0ce8197b18..065aa124ca 100644 --- a/Code/Framework/AzCore/AzCore/IO/SystemFile.h +++ b/Code/Framework/AzCore/AzCore/IO/SystemFile.h @@ -12,10 +12,11 @@ #pragma once #include -#include -#include +#include #include +#include +#include // Establish a consistent size that works across platforms. It's actually larger than this // on platforms we support, but this is a good least common denominator @@ -51,11 +52,15 @@ namespace AZ }; using SizeType = AZ::IO::Internal::SizeType; + using SeekSizeType = AZ::IO::Internal::SeekSizeType; using FileHandleType = AZ::IO::Internal::FileHandleType; SystemFile(); ~SystemFile(); + SystemFile(SystemFile&&); + SystemFile& operator=(SystemFile&&); + /** * Opens a file. * \param fileName full file name including path @@ -69,7 +74,7 @@ namespace AZ /// Closes a file, if file already close it has no effect. void Close(); /// Seek in current file. - void Seek(SizeType offset, SeekMode mode); + void Seek(SeekSizeType offset, SeekMode mode); /// Get the cursor position in the current file. SizeType Tell(); /// Is the cursor at the end of the file? @@ -87,7 +92,7 @@ namespace AZ /// Return disc offset if possible, otherwise 0 SizeType DiskOffset() const; /// Return file name or NULL if file is not open. - AZ_FORCE_INLINE const char* Name() const { return m_fileName; } + AZ_FORCE_INLINE const char* Name() const { return m_fileName.c_str(); } bool IsOpen() const; /// Return native handle to the file. @@ -124,12 +129,12 @@ namespace AZ private: static void CreatePath(const char * fileName); - + bool PlatformOpen(int mode, int platformFlags); void PlatformClose(); - - FileHandleType m_handle; - char m_fileName[AZ_MAX_PATH_LEN]; + + FileHandleType m_handle; + AZ::IO::FixedMaxPathString m_fileName; }; /** diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 2abef3f808..2d2acd9d44 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -641,6 +641,8 @@ namespace AZ::SettingsRegistryMergeUtils } else { + // Set the default ProjectUserPath to the /user directory + registry.Set(FilePathKey_ProjectUserPath, (engineRoot / "user").LexicallyNormal().Native()); AZ_TracePrintf("SettingsRegistryMergeUtils", R"(Project path isn't set in the Settings Registry at "%.*s". Project-related filepaths will not be set)" "\n", aznumeric_cast(projectPathKey.size()), projectPathKey.data()); diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp index 2b1ebf54aa..c9950d2dfa 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp +++ b/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp @@ -101,7 +101,7 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags) createPath = (mode & SF_OPEN_CREATE_PATH) == SF_OPEN_CREATE_PATH; } - bool isApkFile = AZ::Android::Utils::IsApkPath(m_fileName); + bool isApkFile = AZ::Android::Utils::IsApkPath(m_fileName.c_str()); if (createPath) { @@ -111,19 +111,19 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags) return false; } - CreatePath(m_fileName); + CreatePath(m_fileName.c_str()); } int errorCode = 0; if (isApkFile) { AZ::u64 size = 0; - m_handle = AZ::Android::APKFileHandler::Open(m_fileName, openMode, size); + m_handle = AZ::Android::APKFileHandler::Open(m_fileName.c_str(), openMode, size); errorCode = EACCES; // general error when a file can't be opened from inside the APK } else { - m_handle = fopen(m_fileName, openMode); + m_handle = fopen(m_fileName.c_str(), openMode); errorCode = errno; } @@ -233,7 +233,7 @@ namespace Platform } } - void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode) + void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode) { if (handle != PlatformSpecificInvalidHandle) { diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.h b/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.h index 7ccc6a076e..50255f24d4 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.h +++ b/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.h @@ -15,6 +15,9 @@ #include #include #include +#include + +#include namespace AZ { @@ -23,6 +26,7 @@ namespace AZ namespace Internal { using SizeType = AZ::u64; + using SeekSizeType = AZ::s64; using FileHandleType = FILE*; } @@ -37,7 +41,7 @@ namespace AZ #else Temporary = 0, // (Not applicable for this platform) Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified. #endif - Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. + Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. Truncate = O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY. // Note: The TRUNC flag destroys the contents of the specified file. diff --git a/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h b/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h index 902dca4142..3967cafc90 100644 --- a/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h +++ b/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h @@ -22,9 +22,10 @@ namespace AZ namespace Internal { using SizeType = AZ::u64; + using SeekSizeType = AZ::s64; using FileHandleType = int; } - + namespace PosixInternal { enum class OpenFlags : int @@ -36,7 +37,7 @@ namespace AZ #else Temporary = 0, // (Not applicable for this platform) Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified. #endif - Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. + Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. Truncate = O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY. // Note: The TRUNC flag destroys the contents of the specified file. diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/IO/SystemFile_UnixLike.h b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/IO/SystemFile_UnixLike.h index 0f55c0511b..e2d985d84e 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/IO/SystemFile_UnixLike.h +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/IO/SystemFile_UnixLike.h @@ -13,6 +13,9 @@ #include #include +#include + +#include namespace AZ { @@ -21,6 +24,7 @@ namespace AZ namespace Internal { using SizeType = AZ::u64; + using SeekSizeType = AZ::s64; using FileHandleType = int; } @@ -35,7 +39,7 @@ namespace AZ #else Temporary = 0, // (Not applicable for this platform) Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified. #endif - Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. + Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. Truncate = O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY. // Note: The TRUNC flag destroys the contents of the specified file. diff --git a/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp b/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp index 3e40936d66..b5c3041113 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp @@ -86,9 +86,9 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags) if (createPath) { - CreatePath(m_fileName); + CreatePath(m_fileName.c_str()); } - m_handle = open(m_fileName, desiredAccess, permissions); + m_handle = open(m_fileName.c_str(), desiredAccess, permissions); if (m_handle == PlatformSpecificInvalidHandle) { @@ -119,7 +119,7 @@ namespace Platform { using FileHandleType = AZ::IO::SystemFile::FileHandleType; - void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode) + void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode) { if (handle != PlatformSpecificInvalidHandle) { diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp index e01008b1a0..fa77acb967 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp @@ -209,19 +209,19 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags) if (createPath) { - CreatePath(m_fileName); + CreatePath(m_fileName.c_str()); } # ifdef _UNICODE wchar_t fileNameW[AZ_MAX_PATH_LEN]; size_t numCharsConverted; m_handle = INVALID_HANDLE_VALUE; - if (mbstowcs_s(&numCharsConverted, fileNameW, m_fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0) + if (mbstowcs_s(&numCharsConverted, fileNameW, m_fileName.c_str(), AZ_ARRAY_SIZE(fileNameW) - 1) == 0) { m_handle = CreateFileW(fileNameW, dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0); } # else //!_UNICODE - m_handle = CreateFile(m_fileName, dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0); + m_handle = CreateFile(m_fileName.c_str(), dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0); # endif // !_UNICODE if (m_handle == INVALID_HANDLE_VALUE) @@ -261,7 +261,7 @@ namespace Platform { using FileHandleType = AZ::IO::SystemFile::FileHandleType; - void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode) + void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode) { if (handle != PlatformSpecificInvalidHandle) { diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.h b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.h index 7f69a6b66d..09ea48c40b 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.h +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.h @@ -13,6 +13,9 @@ #include #include +#include + +#include namespace AZ { @@ -21,6 +24,7 @@ namespace AZ namespace Internal { using SizeType = AZ::u64; + using SeekSizeType = AZ::s64; using FileHandleType = void*; } @@ -31,7 +35,7 @@ namespace AZ Append = _O_APPEND, // Moves the file pointer to the end of the file before every write operation. Create = _O_CREAT, // Creates a file and opens it for writing. Has no effect if the file specified by filename exists. PermissionMode is required. Temporary = _O_TEMPORARY, // Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified. - Exclusive = _O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. + Exclusive = _O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. Truncate = _O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY. // Note: The TRUNC flag destroys the contents of the specified file. diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index c65ba373f8..bc0c9e537a 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -711,8 +711,8 @@ namespace AzFramework } } - AZ::IO::FixedMaxPath projectUserPath; - if (m_settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath)) + if (AZ::IO::FixedMaxPath projectUserPath; + m_settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath)) { fileIoBase->SetAlias("@user@", projectUserPath.c_str()); AZ::IO::FixedMaxPath projectLogPath = projectUserPath / "log"; @@ -721,6 +721,15 @@ namespace AzFramework CreateUserCache(projectUserPath, *fileIoBase); } + else + { + AZ::IO::FixedMaxPath fallbackLogPath = GetEngineRoot(); + fallbackLogPath /= "user"; + fileIoBase->SetAlias("@user@", fallbackLogPath.c_str()); + fallbackLogPath /= "log"; + fileIoBase->SetAlias("@log@", fallbackLogPath.c_str()); + fileIoBase->CreatePath(fallbackLogPath.c_str()); + } } } diff --git a/Code/Tools/Standalone/Source/LUA/LUAEditorContextInterface.h b/Code/Tools/Standalone/Source/LUA/LUAEditorContextInterface.h index 1bbfe83126..01051f42e3 100644 --- a/Code/Tools/Standalone/Source/LUA/LUAEditorContextInterface.h +++ b/Code/Tools/Standalone/Source/LUA/LUAEditorContextInterface.h @@ -70,6 +70,52 @@ namespace LUAEditor , m_bIsModified(false) , m_bIsBeingSaved(false) , m_PresetLineAtOpen(1){} + + // Copy constructor does not copy over open file handle + DocumentInfo(const DocumentInfo& other) + : m_assetId(other.m_assetId) + , m_scriptAsset(other.m_scriptAsset) + , m_assetName(other.m_assetName) + , m_displayName(other.m_displayName) + , m_lastKnownModTime(other.m_lastKnownModTime) + , m_sourceControlInfo(other.m_sourceControlInfo) + , m_bSourceControl_Ready(other.m_bSourceControl_Ready) + , m_bSourceControl_BusyGettingStats(other.m_bSourceControl_BusyGettingStats) + , m_bSourceControl_BusyRequestingEdit(other.m_bSourceControl_BusyRequestingEdit) + , m_bSourceControl_CanWrite(other.m_bSourceControl_CanWrite) + , m_bSourceControl_CanCheckOut(other.m_bSourceControl_CanCheckOut) + , m_bDataIsLoaded(other.m_bDataIsLoaded) + , m_bDataIsWritten(other.m_bDataIsWritten) + , m_bCloseAfterSave(other.m_bCloseAfterSave) + , m_bUntitledDocument(other.m_bUntitledDocument) + , m_bIsModified(other.m_bIsModified) + , m_bIsBeingSaved(other.m_bIsBeingSaved) + , m_PresetLineAtOpen(other.m_PresetLineAtOpen) + {} + + DocumentInfo& operator=(const DocumentInfo& other) + { + m_assetId = other.m_assetId; + m_scriptAsset = other.m_scriptAsset; + m_assetName = other.m_assetName; + m_displayName = other.m_displayName; + m_lastKnownModTime = other.m_lastKnownModTime; + m_sourceControlInfo = other.m_sourceControlInfo; + m_bSourceControl_Ready = other.m_bSourceControl_Ready; + m_bSourceControl_BusyGettingStats = other.m_bSourceControl_BusyGettingStats; + m_bSourceControl_BusyRequestingEdit = other.m_bSourceControl_BusyRequestingEdit; + m_bSourceControl_CanWrite = other.m_bSourceControl_CanWrite; + m_bSourceControl_CanCheckOut = other.m_bSourceControl_CanCheckOut; + m_bDataIsLoaded = other.m_bDataIsLoaded; + m_bDataIsWritten = other.m_bDataIsWritten; + m_bCloseAfterSave = other.m_bCloseAfterSave; + m_bUntitledDocument = other.m_bUntitledDocument; + m_bIsModified = other.m_bIsModified; + m_bIsBeingSaved = other.m_bIsBeingSaved; + m_PresetLineAtOpen = other.m_PresetLineAtOpen; + + return *this; + } }; class ContextInterface From f20ae8345a398c7fd763638173f1ec76b65970a5 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Thu, 3 Jun 2021 21:58:46 -0700 Subject: [PATCH 39/45] Add Open Project folder menu item --- .../Source/ProjectButtonWidget.cpp | 30 +++++++++---------- .../Source/ProjectButtonWidget.h | 4 --- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp index b1dbd984fb..ee4d48fe7f 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp @@ -11,7 +11,7 @@ */ #include - +#include #include #include @@ -81,18 +81,24 @@ namespace O3DE::ProjectManager m_projectImageLabel = new LabelButton(this); m_projectImageLabel->setFixedSize(s_projectImageWidth, s_projectImageHeight); m_projectImageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); }); vLayout->addWidget(m_projectImageLabel); m_projectImageLabel->setPixmap( QPixmap(m_projectInfo.m_imagePath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding)); - QMenu* newProjectMenu = new QMenu(this); - m_editProjectAction = newProjectMenu->addAction(tr("Edit Project Settings...")); - newProjectMenu->addSeparator(); - m_copyProjectAction = newProjectMenu->addAction(tr("Duplicate")); - newProjectMenu->addSeparator(); - m_removeProjectAction = newProjectMenu->addAction(tr("Remove from O3DE")); - m_deleteProjectAction = newProjectMenu->addAction(tr("Delete this Project")); + QMenu* menu = new QMenu(this); + menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); }); + menu->addSeparator(); + menu->addAction(tr("Open Project folder..."), this, [this]() + { + AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path); + }); + menu->addSeparator(); + menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo.m_path); }); + menu->addSeparator(); + menu->addAction(tr("Remove from O3DE"), this, [this]() { emit RemoveProject(m_projectInfo.m_path); }); + menu->addAction(tr("Delete this Project"), this, [this]() { emit DeleteProject(m_projectInfo.m_path); }); QFrame* footer = new QFrame(this); QHBoxLayout* hLayout = new QHBoxLayout(); @@ -104,17 +110,11 @@ namespace O3DE::ProjectManager QPushButton* projectMenuButton = new QPushButton(this); projectMenuButton->setObjectName("projectMenuButton"); - projectMenuButton->setMenu(newProjectMenu); + projectMenuButton->setMenu(menu); hLayout->addWidget(projectMenuButton); } vLayout->addWidget(footer); - - connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); }); - connect(m_editProjectAction, &QAction::triggered, [this]() { emit EditProject(m_projectInfo.m_path); }); - connect(m_copyProjectAction, &QAction::triggered, [this]() { emit CopyProject(m_projectInfo.m_path); }); - connect(m_removeProjectAction, &QAction::triggered, [this]() { emit RemoveProject(m_projectInfo.m_path); }); - connect(m_deleteProjectAction, &QAction::triggered, [this]() { emit DeleteProject(m_projectInfo.m_path); }); } void ProjectButton::SetButtonEnabled(bool enabled) diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h index 3ac69b7603..bb61f7354b 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h @@ -71,9 +71,5 @@ namespace O3DE::ProjectManager ProjectInfo m_projectInfo; LabelButton* m_projectImageLabel; - QAction* m_editProjectAction; - QAction* m_copyProjectAction; - QAction* m_removeProjectAction; - QAction* m_deleteProjectAction; }; } // namespace O3DE::ProjectManager From 05e20803a89253bd8f7ba6ef507242e08d833d72 Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Fri, 4 Jun 2021 14:32:06 +0100 Subject: [PATCH 40/45] First pass for getting things ready for grid snap button (#1118) * first pass of change to simplify snapping for snap-to-grid button and fix snapping bug caused by non-uniform scale --- .../AzManipulatorTestFrameworkUtils.h | 25 ++-- .../AzManipulatorTestFrameworkUtils.cpp | 58 +++++---- .../Tests/GridSnappingTest.cpp | 120 +++++++++++++----- .../Manipulators/BaseManipulator.cpp | 5 + .../Manipulators/EditorVertexSelection.cpp | 27 ++-- .../Manipulators/LinearManipulator.cpp | 70 ++++------ .../Manipulators/LinearManipulator.h | 12 +- .../Manipulators/ManipulatorSnapping.cpp | 36 ++++-- .../Manipulators/ManipulatorSnapping.h | 22 ++-- .../Manipulators/MultiLinearManipulator.cpp | 28 ++-- .../Manipulators/MultiLinearManipulator.h | 2 - .../Manipulators/PlanarManipulator.cpp | 50 +++----- .../Manipulators/PlanarManipulator.h | 13 +- .../EditorNonUniformScaleComponentMode.cpp | 48 ++++--- .../EditorTransformComponentSelection.cpp | 39 ++---- 15 files changed, 295 insertions(+), 260 deletions(-) diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h index dcddf1e5a5..f1c32e4d8d 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h @@ -12,17 +12,22 @@ #pragma once -#include -#include #include +#include +#include +#include namespace AzManipulatorTestFramework { - //! Create a linear manipulator with a unit sphere bounds. + //! Create a linear manipulator with a unit sphere bound. AZStd::shared_ptr CreateLinearManipulator( - const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, - const AZ::Vector3& position = AZ::Vector3::CreateZero(), - const float radius = 1.0f); + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position = AZ::Vector3::CreateZero(), + float radius = 1.0f); + + //! Create a planar manipulator with a unit sphere bound. + AZStd::shared_ptr CreatePlanarManipulator( + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position = AZ::Vector3::CreateZero(), + float radius = 1.0f); //! Create a mouse pick from the specified ray and screen point. AzToolsFramework::ViewportInteraction::MousePick CreateMousePick( @@ -34,14 +39,12 @@ namespace AzManipulatorTestFramework //! Create a mouse interaction from the specified pick, buttons, interaction id and keyboard modifiers. AzToolsFramework::ViewportInteraction::MouseInteraction CreateMouseInteraction( - const AzToolsFramework::ViewportInteraction::MousePick& mousePick, - AzToolsFramework::ViewportInteraction::MouseButtons buttons, + const AzToolsFramework::ViewportInteraction::MousePick& mousePick, AzToolsFramework::ViewportInteraction::MouseButtons buttons, AzToolsFramework::ViewportInteraction::InteractionId interactionId, AzToolsFramework::ViewportInteraction::KeyboardModifiers modifiers); //! Create a mouse buttons from the specified mouse button. - AzToolsFramework::ViewportInteraction::MouseButtons CreateMouseButtons( - AzToolsFramework::ViewportInteraction::MouseButton button); + AzToolsFramework::ViewportInteraction::MouseButtons CreateMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton button); //! Create a mouse interaction event from the specified interaction and event. AzToolsFramework::ViewportInteraction::MouseInteractionEvent CreateMouseInteractionEvent( @@ -61,5 +64,5 @@ namespace AzManipulatorTestFramework AzFramework::ScreenPoint GetCameraStateViewportCenter(const AzFramework::CameraState& cameraState); //! Default viewport size (1080p) in 16:9 aspect ratio. - const auto DefaultViewportSize = AZ::Vector2(1920.0f, 1080.0f); + inline const auto DefaultViewportSize = AZ::Vector2(1920.0f, 1080.0f); } // namespace AzManipulatorTestFramework diff --git a/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp b/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp index b255fcae73..985c21cf8e 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include namespace AzManipulatorTestFramework @@ -28,22 +27,21 @@ namespace AzManipulatorTestFramework using MouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent; using MousePick = AzToolsFramework::ViewportInteraction::MousePick; - AZStd::shared_ptr CreateLinearManipulator( - const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, - const AZ::Vector3& position, - const float radius) + // create a default sphere view for a manipulator for simple intersection + template + void SetupManipulatorView( + AZStd::shared_ptr manipulator, const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, + const AZ::Vector3& position, const float radius) { - auto manipulator = AzToolsFramework::LinearManipulator::MakeShared(AZ::Transform::CreateIdentity()); - manipulator->SetLocalPosition(position); - // unit sphere view auto sphereView = AzToolsFramework::CreateManipulatorViewSphere( AZ::Colors::Red, radius, - [](const MouseInteraction& /*mouseInteraction*/, const bool /*mouseOver*/, - const AZ::Color& defaultColor) - { - return defaultColor; - }, true); + []([[maybe_unused]] const MouseInteraction& mouseInteraction, [[maybe_unused]] const bool mouseOver, + const AZ::Color& defaultColor) + { + return defaultColor; + }, + true); // unit sphere bound AzToolsFramework::Picking::BoundShapeSphere sphereBound; @@ -62,6 +60,26 @@ namespace AzManipulatorTestFramework // this would occur internally when the manipulator is drawn but we must do manually here to ensure that the // bounds will always be valid upon instantiation view->RefreshBound(manipulatorManagerId, manipulator->GetManipulatorId(), sphereBound); + } + + AZStd::shared_ptr CreateLinearManipulator( + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position, const float radius) + { + auto manipulator = AzToolsFramework::LinearManipulator::MakeShared(AZ::Transform::CreateIdentity()); + manipulator->SetLocalPosition(position); + + SetupManipulatorView(manipulator, manipulatorManagerId, position, radius); + + return manipulator; + } + + AZStd::shared_ptr CreatePlanarManipulator( + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position, const float radius) + { + auto manipulator = AzToolsFramework::PlanarManipulator::MakeShared(AZ::Transform::CreateIdentity()); + manipulator->SetLocalPosition(position); + + SetupManipulatorView(manipulator, manipulatorManagerId, position, radius); return manipulator; } @@ -104,8 +122,7 @@ namespace AzManipulatorTestFramework return buttons; } - MouseInteractionEvent CreateMouseInteractionEvent( - const MouseInteraction& mouseInteraction, MouseEvent event) + MouseInteractionEvent CreateMouseInteractionEvent(const MouseInteraction& mouseInteraction, MouseEvent event) { return MouseInteractionEvent(mouseInteraction, event); } @@ -114,8 +131,7 @@ namespace AzManipulatorTestFramework { AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Event( AzToolsFramework::GetEntityContextId(), - &AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions, - event); + &AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions, event); } AzFramework::CameraState SetCameraStatePosition(const AZ::Vector3& position, AzFramework::CameraState& cameraState) @@ -133,9 +149,7 @@ namespace AzManipulatorTestFramework AzFramework::ScreenPoint GetCameraStateViewportCenter(const AzFramework::CameraState& cameraState) { - return { - aznumeric_cast(cameraState.m_viewportSize.GetX() / 2.f), - aznumeric_cast(cameraState.m_viewportSize.GetY() / 2.f) - }; + return { aznumeric_cast(cameraState.m_viewportSize.GetX() / 2.f), + aznumeric_cast(cameraState.m_viewportSize.GetY() / 2.f) }; } -} // namespace UnitTest +} // namespace AzManipulatorTestFramework diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp index e6468c1ebb..d6006ba74f 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp @@ -10,52 +10,55 @@ * */ +#include "AzManipulatorTestFrameworkTestFixtures.h" + #include #include #include -#include "AzManipulatorTestFrameworkTestFixtures.h" -#include -#include -#include #include +#include +#include +#include +#include +#include #include +#include namespace UnitTest { - class GridSnappingFixture - : public ToolsApplicationFixture + class GridSnappingFixture : public ToolsApplicationFixture { public: GridSnappingFixture() : m_viewportManipulatorInteraction(AZStd::make_unique()) - , m_actionDispatcher(AZStd::make_unique(*m_viewportManipulatorInteraction)) - , m_linearManipulator( - AzManipulatorTestFramework::CreateLinearManipulator( - m_viewportManipulatorInteraction->GetManipulatorManager().GetId(), - /*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f), - /*radius=*/m_boundsRadius)) - {} + , m_actionDispatcher( + AZStd::make_unique(*m_viewportManipulatorInteraction)) + { + } protected: void SetUpEditorFixtureImpl() override { - m_cameraState = AzFramework::CreateIdentityDefaultCamera( - AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); + m_cameraState = + AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); } public: - const float m_boundsRadius = 1.0f; AZStd::unique_ptr m_viewportManipulatorInteraction; AZStd::unique_ptr m_actionDispatcher; - AZStd::shared_ptr m_linearManipulator; AzFramework::CameraState m_cameraState; }; TEST_F(GridSnappingFixture, MouseDownWithSnappingEnabledSnapsToClosestGridSize) { + AZStd::shared_ptr linearManipulator(AzManipulatorTestFramework::CreateLinearManipulator( + m_viewportManipulatorInteraction->GetManipulatorManager().GetId(), + /*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f), + /*radius=*/m_boundsRadius)); + // the initial starting position of the manipulator (in front of the camera) - const auto initialPositionWorld = m_linearManipulator->GetLocalPosition(); + const auto initialPositionWorld = linearManipulator->GetLocalPosition(); // where the manipulator should end up (in front and to the left of the camera) const auto finalPositionWorld = AZ::Vector3(-10.0f, 50.0f, 0.0f); // perspective scale factor for manipulator distance to camera @@ -66,21 +69,18 @@ namespace UnitTest // adjusted final world position taking into account the manipulator position relative to the camera const auto finalPositionWorldAdjusted = finalPositionWorld - (vectorToInitialPositionWorld * scaledRadiusBound); // calculate the position in screen space of the initial position of the manipulator - const auto initialPositionScreen = - AzFramework::WorldToScreen(initialPositionWorld, m_cameraState); + const auto initialPositionScreen = AzFramework::WorldToScreen(initialPositionWorld, m_cameraState); // calculate the position in screen space of the final position of the manipulator const auto finalPositionScreen = AzFramework::WorldToScreen(finalPositionWorldAdjusted, m_cameraState); // callback to update the manipulator's current position - m_linearManipulator->InstallMouseMoveCallback( - [this](const AzToolsFramework::LinearManipulator::Action& action) - { - auto pos = action.LocalPosition(); - m_linearManipulator->SetLocalPosition(pos); - }); + linearManipulator->InstallMouseMoveCallback( + [this, linearManipulator](const AzToolsFramework::LinearManipulator::Action& action) + { + linearManipulator->SetLocalPosition(action.LocalPosition()); + }); - m_actionDispatcher - ->EnableSnapToGrid() + m_actionDispatcher->EnableSnapToGrid() ->GridSize(5.0f) ->CameraState(m_cameraState) ->MousePosition(initialPositionScreen) @@ -89,7 +89,67 @@ namespace UnitTest ->MousePosition(finalPositionScreen) ->MouseLButtonUp() ->ExpectManipulatorNotBeingInteracted() - ->ExpectTrue(m_linearManipulator->GetLocalPosition().IsClose(finalPositionWorld, 0.01f)) - ; + ->ExpectTrue(linearManipulator->GetLocalPosition().IsClose(finalPositionWorld, 0.01f)); + } + + template + void ValidateManipulatorSnappingBehavior( + AZStd::shared_ptr manipulator, AzManipulatorTestFramework::ImmediateModeActionDispatcher* actionDispatcher, + const AzFramework::CameraState& cameraState) + { + manipulator->SetLocalOrientation(AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(180.0f, 0.0f, 135.0f))); + + // the initial starting position of the manipulator (in front of the camera) + const auto initialPositionWorld = manipulator->GetLocalPosition() + AZ::Vector3::CreateAxisX(0.15f); + // where the manipulator should end up (unmoved) + const auto finalPositionWorld = manipulator->GetLocalPosition(); + // where we should move the mouse to + const auto attemptPositionWorld = manipulator->GetLocalPosition() + AZ::Vector3::CreateAxisX(0.35f); + // calculate the position in screen space of the initial position of the manipulator + const auto initialPositionScreen = AzFramework::WorldToScreen(initialPositionWorld, cameraState); + // calculate the position in screen space of the final position of the manipulator + const auto attemptPositionScreen = AzFramework::WorldToScreen(attemptPositionWorld, cameraState); + + // callback to update the manipulator's current position + manipulator->InstallMouseMoveCallback( + [manipulator](const typename Manipulator::Action& action) + { + manipulator->SetLocalPosition(action.LocalPosition()); + }); + + actionDispatcher->EnableSnapToGrid() + ->GridSize(1.0f) + ->CameraState(cameraState) + ->MousePosition(initialPositionScreen) + ->MouseLButtonDown() + ->ExpectManipulatorBeingInteracted() + ->MousePosition(attemptPositionScreen) + ->MouseLButtonUp() + ->ExpectManipulatorNotBeingInteracted() + ->ExpectThat(manipulator->GetLocalPosition(), IsCloseTolerance(finalPositionWorld, 0.01f)); + } + + TEST_F(GridSnappingFixture, MouseDownAndMoveLinearManipulatorDoesNotSnapWithMovementSmallerThanHalfGridSize) + { + AZStd::shared_ptr linearManipulator(AzManipulatorTestFramework::CreateLinearManipulator( + m_viewportManipulatorInteraction->GetManipulatorManager().GetId(), + /*position=*/AZ::Vector3(0.0f, 10.0f, 0.0f), + /*radius=*/m_boundsRadius)); + + linearManipulator->SetAxis(AZ::Vector3::CreateAxisY()); + + ValidateManipulatorSnappingBehavior(linearManipulator, m_actionDispatcher.get(), m_cameraState); + } + + TEST_F(GridSnappingFixture, MouseDownAndMovePlanarManipulatorDoesNotSnapWithMovementSmallerThanHalfGridSize) + { + AZStd::shared_ptr planarManipulator(AzManipulatorTestFramework::CreatePlanarManipulator( + m_viewportManipulatorInteraction->GetManipulatorManager().GetId(), + /*position=*/AZ::Vector3(0.0f, 10.0f, 0.0f), + /*radius=*/m_boundsRadius)); + + planarManipulator->SetAxes(AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + + ValidateManipulatorSnappingBehavior(planarManipulator, m_actionDispatcher.get(), m_cameraState); } } // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp index e7235f0f82..955d10d3bd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp @@ -433,6 +433,11 @@ namespace AzToolsFramework return m_manipulatorSpaceWithLocalTransform.GetSpace(); } + const AZ::Vector3& Manipulators::GetNonUniformScale() const + { + return m_manipulatorSpaceWithLocalTransform.GetNonUniformScale(); + } + void Manipulators::SetSpace(const AZ::Transform& worldFromLocal) { m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp index 4d10a4c171..55a8464ba6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp @@ -192,8 +192,7 @@ namespace AzToolsFramework /// for each vertex associated with the translation manipulator to use with offset calculations when updating. template void InitializeVertexLookup( - IndexedTranslationManipulator& translationManipulator, - const AZ::EntityId entityId, const AZ::Vector3& snapOffset) + IndexedTranslationManipulator& translationManipulator, const AZ::EntityId entityId) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -202,7 +201,7 @@ namespace AzToolsFramework AZ::FixedVerticesRequestBus::Bind(fixedVertices, entityId); translationManipulator.Process( - [snapOffset, fixedVertices] + [fixedVertices] (typename IndexedTranslationManipulator::VertexLookup& vertexLookup) { Vertex vertex; @@ -213,7 +212,7 @@ namespace AzToolsFramework if (found) { - vertexLookup.m_start = vertex + AZ::AdaptVertexIn(snapOffset); + vertexLookup.m_start = vertex; vertexLookup.m_offset = Vertex::CreateZero(); } }); @@ -250,10 +249,10 @@ namespace AzToolsFramework // linear manipulator callbacks m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseDownCallback( - [this](const LinearManipulator::Action& action) + [this]([[maybe_unused]] const LinearManipulator::Action& action) { BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_positionSnapOffset); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); }); m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseMoveCallback( @@ -264,17 +263,17 @@ namespace AzToolsFramework }); m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseUpCallback( - [this](const LinearManipulator::Action& /*action*/) + [this]([[maybe_unused]] const LinearManipulator::Action& action) { EndBatchMovement(); }); // planar manipulator callbacks m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseDownCallback( - [this](const PlanarManipulator::Action& action) + [this]([[maybe_unused]] const PlanarManipulator::Action& action) { BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_snapOffset); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); }); m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseMoveCallback( @@ -285,17 +284,17 @@ namespace AzToolsFramework }); m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseUpCallback( - [this](const PlanarManipulator::Action& /*action*/) + [this]([[maybe_unused]] const PlanarManipulator::Action& action) { EndBatchMovement(); }); // surface manipulator callbacks m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseDownCallback( - [this](const SurfaceManipulator::Action& action) + [this]([[maybe_unused]] const SurfaceManipulator::Action& action) { BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_snapOffset); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); }); m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseMoveCallback( @@ -306,7 +305,7 @@ namespace AzToolsFramework }); m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseUpCallback( - [this](const SurfaceManipulator::Action& /*action*/) + [this]([[maybe_unused]] const SurfaceManipulator::Action& action) { EndBatchMovement(); }); @@ -893,7 +892,7 @@ namespace AzToolsFramework { BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId(), AZ::Vector3::CreateZero()); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); // note: AdaptVertexIn/Out is to ensure we clamp the vertex local Z position to 0 if // dealing with Vector2s when setting the position of the manipulator. const AZ::Vector3 localOffset = diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp index aa84fc5752..34ae28bd13 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp @@ -23,8 +23,8 @@ namespace AzToolsFramework { LinearManipulator::Starter CalculateLinearManipulationDataStart( const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction, - const float intersectionDistance, const AzFramework::CameraState& cameraState) + const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance, + const AzFramework::CameraState& cameraState) { const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction( @@ -50,28 +50,9 @@ namespace AzToolsFramework manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, localIntersectionPoint, startTransition.m_localNormal, start.m_localHitPosition); - const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize; - const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap; - const float scaleRecip = manipulatorInteraction.m_scaleReciprocal; - - // calculate position amount to snap, to align with grid - const AZ::Vector3 positionSnapOffset = snapping && !gridSnapAction.m_localSnapping - ? CalculateSnappedOffset(localTransform.GetTranslation(), axis, gridSize * scaleRecip) - : AZ::Vector3::CreateZero(); - - const AZ::Vector3 localScale = AZ::Vector3(localTransform.GetUniformScale()); - const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform); - // calculate scale amount to snap, to align to round scale value - const AZ::Vector3 scaleSnapOffset = snapping && !gridSnapAction.m_localSnapping - ? localRotation.GetInverseFull().TransformVector(CalculateSnappedOffset( - localRotation.TransformVector(localScale), axis, gridSize * scaleRecip)) - : AZ::Vector3::CreateZero(); - start.m_screenPosition = interaction.m_mousePick.m_screenCoordinates; - start.m_positionSnapOffset = positionSnapOffset; - start.m_scaleSnapOffset = scaleSnapOffset; - start.m_localPosition = localTransform.GetTranslation() + positionSnapOffset; - start.m_localScale = localScale + scaleSnapOffset; + start.m_localPosition = localTransform.GetTranslation(); + start.m_localScale = AZ::Vector3(localTransform.GetUniformScale());; start.m_localAxis = axis; // sign to determine which side of the linear axis we pressed // (useful to know when the visual axis flips to face the camera) @@ -87,7 +68,7 @@ namespace AzToolsFramework LinearManipulator::Action CalculateLinearManipulationDataAction( const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, - const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction) + const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction) { const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction( @@ -108,31 +89,34 @@ namespace AzToolsFramework GetCameraState(interaction.m_interactionId.m_viewportId)); const AZ::Vector3 axis = TransformDirectionNoScaling(localTransform, fixed.m_axis); - // The local positions have been transformed to the reference frame of the object being manipulated. But they appear in the world - // with non-uniform scale applied, and the object being manipulated will want to work with unscaled deltas, so we need to divide by - // the non-uniform scale here. + // the local positions have been transformed to the reference frame of the object being manipulated, but they appear in the world + // with non-uniform scale applied, the object being manipulated will want to work with unscaled deltas, so we need to divide by + // the non-uniform scale here const AZ::Vector3 hitDelta = (localHitPosition - start.m_localHitPosition) / nonUniformScale; const AZ::Vector3 unsnappedOffset = axis * axis.Dot(hitDelta); - const float scaleRecip = manipulatorInteraction.m_scaleReciprocal * axis.Dot(manipulatorInteraction.m_nonUniformScaleReciprocal); - const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize; - const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap; + const float scaleRecip = + manipulatorInteraction.m_scaleReciprocal * fixed.m_axis.Dot(manipulatorInteraction.m_nonUniformScaleReciprocal); + const float gridSize = gridSnapParams.m_gridSize; + const bool snapping = gridSnapParams.m_gridSnap; LinearManipulator::Action action; action.m_fixed = fixed; action.m_start = start; action.m_current.m_localPositionOffset = snapping - ? unsnappedOffset + CalculateSnappedOffset(unsnappedOffset, axis, gridSize * scaleRecip) + ? CalculateSnappedAmount(unsnappedOffset, axis, gridSize * scaleRecip) : unsnappedOffset; action.m_current.m_screenPosition = interaction.m_mousePick.m_screenCoordinates; action.m_viewportId = interaction.m_interactionId.m_viewportId; const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform); - const AZ::Vector3 scaledUnsnappedOffset = unsnappedOffset * startTransition.m_screenToWorldScale * NonUniformScaleReciprocal(nonUniformScale); + const AZ::Vector3 scaledUnsnappedOffset = + unsnappedOffset * startTransition.m_screenToWorldScale * NonUniformScaleReciprocal(nonUniformScale); + // how much to adjust the scale based on movement const AZ::Quaternion invLocalRotation = localRotation.GetInverseFull(); action.m_current.m_localScaleOffset = snapping - ? invLocalRotation.TransformVector((scaledUnsnappedOffset + CalculateSnappedOffset(scaledUnsnappedOffset, axis, gridSize * scaleRecip))) + ? invLocalRotation.TransformVector(CalculateSnappedAmount(scaledUnsnappedOffset, axis, gridSize * scaleRecip)) : invLocalRotation.TransformVector(scaledUnsnappedOffset); // record what modifier keys are held during this action @@ -171,19 +155,18 @@ namespace AzToolsFramework const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance) { const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); - const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); // note: m_localTransform must not be made uniform as it may contain a local scale we want to snap m_starter = CalculateLinearManipulationDataStart( - m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction, rayIntersectionDistance, + m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, rayIntersectionDistance, GetCameraState(interaction.m_interactionId.m_viewportId)); if (m_onLeftMouseDownCallback) { + const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); + m_onLeftMouseDownCallback(CalculateLinearManipulationDataAction( - m_fixed, m_starter, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + m_fixed, m_starter, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), gridSnapParams, interaction)); } } @@ -195,8 +178,8 @@ namespace AzToolsFramework // note: m_localTransform must not be made uniform as it may contain a local scale we want to snap m_onMouseMoveCallback(CalculateLinearManipulationDataAction( - m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, + interaction)); } } @@ -208,8 +191,7 @@ namespace AzToolsFramework // note: m_localTransform must not be made uniform as it may contain a local scale we want to snap m_onLeftMouseUpCallback(CalculateLinearManipulationDataAction( - m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, interaction)); } } @@ -232,8 +214,8 @@ namespace AzToolsFramework GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId); const auto action = CalculateLinearManipulationDataAction( - m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, mouseInteraction.m_keyboardModifiers.Alt()), mouseInteraction); + m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, + mouseInteraction); // display the exact hit (ray intersection) of the mouse pick on the manipulator DrawTransformAxes( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h index 576c543dce..c3d43a2535 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h @@ -20,7 +20,7 @@ namespace AzToolsFramework { - struct GridSnapAction; + struct GridSnapParameters; /// LinearManipulator serves as a visual tool for users to modify values /// in one dimension on an axis defined in 3D space. @@ -68,8 +68,6 @@ namespace AzToolsFramework AZ::Vector3 m_localScale; ///< The current scale of the manipulator in local space. AZ::Vector3 m_localHitPosition; ///< The intersection point in local space between the ray and the manipulator when the mouse down event happens. AZ::Vector3 m_localAxis; ///< The axis in the local space of the manipulator itself. - AZ::Vector3 m_positionSnapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid. - AZ::Vector3 m_scaleSnapOffset; ///< The snap offset amount to ensure manipulator is aligned to round scale increments. float m_sign; ///< Used to determine which side of the axis we clicked on in case it's flipped to face the camera. AzFramework::ScreenPoint m_screenPosition; ///< The initial position in screen space of the manipulator. }; @@ -91,7 +89,7 @@ namespace AzToolsFramework ViewportInteraction::KeyboardModifiers m_modifiers; int m_viewportId; ///< The id of the viewport this manipulator is being used in. AZ::Vector3 LocalScale() const { return m_start.m_localScale + m_current.m_localScaleOffset; } - AZ::Vector3 LocalScaleOffset() const { return m_start.m_scaleSnapOffset + m_current.m_localScaleOffset; } + AZ::Vector3 LocalScaleOffset() const { return m_current.m_localScaleOffset; } AZ::Vector3 LocalPosition() const { return m_start.m_localPosition + m_current.m_localPositionOffset; } AZ::Vector3 LocalPositionOffset() const { return m_current.m_localPositionOffset; } AZ::Vector2 ScreenOffset() const @@ -162,11 +160,11 @@ namespace AzToolsFramework LinearManipulator::Starter CalculateLinearManipulationDataStart( const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction, - float intersectionDistance, const AzFramework::CameraState& cameraState); + const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance, + const AzFramework::CameraState& cameraState); LinearManipulator::Action CalculateLinearManipulationDataAction( const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, - const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction); + const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp index 015ea8a3e3..8a6398d025 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp @@ -42,12 +42,6 @@ namespace AzToolsFramework { } - GridSnapAction::GridSnapAction(const GridSnapParameters& gridSnapParameters, const bool localSnapping) - : m_gridSnapParams(gridSnapParameters) - , m_localSnapping(localSnapping) - { - } - ManipulatorInteraction BuildManipulatorInteraction( const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection) @@ -57,19 +51,39 @@ namespace AzToolsFramework return {localFromWorldUniform.TransformPoint(worldRayOrigin), TransformDirectionNoScaling(localFromWorldUniform, worldRayDirection), - ScaleReciprocal(worldFromLocalUniform), - NonUniformScaleReciprocal(nonUniformScale)}; + NonUniformScaleReciprocal(nonUniformScale), + ScaleReciprocal(worldFromLocalUniform)}; } - AZ::Vector3 CalculateSnappedOffset( - const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size) + struct SnapAdjustment + { + float m_existingSnapDistance; //!< How far to snap up or down to align to the grid. + float m_nextSnapDistance; //!< The snap increment (will return full signed value (grid size) when distance + //!< moved is greater than half of the grid size in either direction). + }; + + static SnapAdjustment CalculateSnapDistance(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size) { // calculate total distance along axis const float axisDistance = axis.Dot(unsnappedPosition); // round to nearest step size const float snappedAxisDistance = floorf((axisDistance / size) + 0.5f) * size; + + return { axisDistance, snappedAxisDistance }; + } + + AZ::Vector3 CalculateSnappedOffset(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size) + { + const auto snapAdjustment = CalculateSnapDistance(unsnappedPosition, axis, size); // return offset along axis to snap to step size - return axis * (snappedAxisDistance - axisDistance); + return axis * (snapAdjustment.m_nextSnapDistance - snapAdjustment.m_existingSnapDistance); + } + + AZ::Vector3 CalculateSnappedAmount(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size) + { + const auto snapAdjustment = CalculateSnapDistance(unsnappedPosition, axis, size); + // return offset along axis to snap to step size + return axis * snapAdjustment.m_nextSnapDistance; } AZ::Vector3 CalculateSnappedTerrainPosition( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h index e6c70079df..11860780c7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h @@ -31,24 +31,15 @@ namespace AzToolsFramework float m_gridSize; }; - /// Structure to encapsulate the current grid snapping state. - struct GridSnapAction - { - GridSnapAction(const GridSnapParameters& gridSnapParameters, bool localSnapping); - - GridSnapParameters m_gridSnapParams; - bool m_localSnapping; - }; - /// Structure to hold transformed incoming viewport interaction from world space to manipulator space. struct ManipulatorInteraction { AZ::Vector3 m_localRayOrigin; ///< The ray origin (start) in the reference from of the manipulator. AZ::Vector3 m_localRayDirection; ///< The ray direction in the reference from of the manipulator. - float m_scaleReciprocal; ///< The scale reciprocal (1.0 / scale) of the transform used to move the - ///< ray from world space to local space. AZ::Vector3 m_nonUniformScaleReciprocal; ///< Handles inverting any non-uniform scale which was applied ///< separately from the transform. + float m_scaleReciprocal; ///< The scale reciprocal (1.0 / scale) of the transform used to move the + ///< ray from world space to local space. }; /// Build a ManipulatorInteraction structure from the incoming viewport interaction. @@ -56,11 +47,16 @@ namespace AzToolsFramework const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection); - /// Calculate the offset along an axis to adjust a position - /// to stay snapped to a given grid size. + /// Calculate the offset along an axis to adjust a position to stay snapped to a given grid size. + /// @note This is snap up or down to the nearest grid segment (e.g. 0.2 snaps to 0.0 -> delta 0.2, + /// 0.7 snaps to 1.0 -> delta 0.3). AZ::Vector3 CalculateSnappedOffset( const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size); + /// Return the amount to snap from the starting position given the current grid size. + /// @note A movement of more than half size (in either direction) will cause a snap by size. + AZ::Vector3 CalculateSnappedAmount(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size); + /// For a given point on the terrain, calculate the closest xy position snapped to the grid /// (z position is aligned to terrain height, not snapped to z grid) AZ::Vector3 CalculateSnappedTerrainPosition( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp index 566de9a8a6..83c4c28e9a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp @@ -59,17 +59,16 @@ namespace AzToolsFramework const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, const AZStd::vector& fixedAxes, - const AZStd::vector& starterStates, const GridSnapAction& gridSnapAction) + const AZStd::vector& starterStates, const GridSnapParameters& gridSnapParams) { MultiLinearManipulator::Action action; action.m_viewportId = interaction.m_interactionId.m_viewportId; // build up action state for each axis for (size_t fixedIndex = 0; fixedIndex < fixedAxes.size(); ++fixedIndex) { - action.m_actions.push_back( - CalculateLinearManipulationDataAction( - fixedAxes[fixedIndex], starterStates[fixedIndex], worldFromLocal, nonUniformScale, localTransform, - gridSnapAction, interaction)); + action.m_actions.push_back(CalculateLinearManipulationDataAction( + fixedAxes[fixedIndex], starterStates[fixedIndex], worldFromLocal, nonUniformScale, localTransform, gridSnapParams, + interaction)); } return action; @@ -79,8 +78,6 @@ namespace AzToolsFramework const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance) { const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); - - const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); const AzFramework::CameraState cameraState = GetCameraState(interaction.m_interactionId.m_viewportId); // build up initial start state for each axis @@ -88,20 +85,19 @@ namespace AzToolsFramework { // note: m_localTransform must not be made uniform as it may contain a local scale we want to snap const auto linearStart = CalculateLinearManipulationDataStart( - fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction, - rayIntersectionDistance, cameraState); + fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, rayIntersectionDistance, + cameraState); m_starters.push_back(linearStart); } if (m_onLeftMouseDownCallback) { - const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()); + const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); // pass action containing all linear actions for each axis to handler m_onLeftMouseDownCallback(BuildMultiLinearManipulatorAction( worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - interaction, m_fixedAxes, m_starters, gridSnapAction)); + interaction, m_fixedAxes, m_starters, gridSnapParams)); } } @@ -111,11 +107,9 @@ namespace AzToolsFramework { const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); - const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()); - m_onMouseMoveCallback(BuildMultiLinearManipulatorAction( worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - interaction, m_fixedAxes, m_starters, gridSnapAction)); + interaction, m_fixedAxes, m_starters, gridSnapParams)); } } @@ -125,11 +119,9 @@ namespace AzToolsFramework { const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); - const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()); - m_onLeftMouseUpCallback(BuildMultiLinearManipulatorAction( worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - interaction, m_fixedAxes, m_starters, gridSnapAction)); + interaction, m_fixedAxes, m_starters, gridSnapParams)); m_starters.clear(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h index 4a99435008..8e31e02605 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h @@ -20,8 +20,6 @@ namespace AzToolsFramework { - struct GridSnapAction; - //! MultiLinearManipulator serves as a visual tool for users to modify values //! in one or more dimensions on axes defined in 3D space. class MultiLinearManipulator diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp index abd5414ce3..6eb96f081c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp @@ -22,8 +22,7 @@ namespace AzToolsFramework { PlanarManipulator::StartInternal PlanarManipulator::CalculateManipulationDataStart( - const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, + const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance) { const ManipulatorInteraction manipulatorInteraction = @@ -31,8 +30,6 @@ namespace AzToolsFramework worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection); const AZ::Vector3 normal = TransformDirectionNoScaling(localTransform, fixed.m_normal); - const AZ::Vector3 axis1 = TransformDirectionNoScaling(localTransform, fixed.m_axis1); - const AZ::Vector3 axis2 = TransformDirectionNoScaling(localTransform, fixed.m_axis2); // initial intersect point const AZ::Vector3 localIntersectionPoint = @@ -43,25 +40,14 @@ namespace AzToolsFramework manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, localIntersectionPoint, normal, startInternal.m_localHitPosition); - const float scaleRecip = manipulatorInteraction.m_scaleReciprocal; - const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize; - const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap; - - // calculate amount to snap to align with grid - const AZ::Vector3 snapOffset = snapping && !gridSnapAction.m_localSnapping - ? CalculateSnappedOffset(localTransform.GetTranslation(), axis1, gridSize * scaleRecip) + - CalculateSnappedOffset(localTransform.GetTranslation(), axis2, gridSize * scaleRecip) - : AZ::Vector3::CreateZero(); - - startInternal.m_snapOffset = snapOffset; - startInternal.m_localPosition = localTransform.GetTranslation() + snapOffset; + startInternal.m_localPosition = localTransform.GetTranslation(); return startInternal; } PlanarManipulator::Action PlanarManipulator::CalculateManipulationDataAction( - const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, - const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, + const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction) { const ManipulatorInteraction manipulatorInteraction = @@ -88,20 +74,18 @@ namespace AzToolsFramework const AZ::Vector3 hitDelta = (localHitPosition - startInternal.m_localHitPosition) / nonUniformScale; const AZ::Vector3 unsnappedOffset = axis1.Dot(hitDelta) * axis1 + axis2.Dot(hitDelta) * axis2; - const float scaleRecip = manipulatorInteraction.m_scaleReciprocal; const AZ::Vector3 nonUniformScaleRecip = manipulatorInteraction.m_nonUniformScaleReciprocal; - const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize; - const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap; + const float scaleRecip = manipulatorInteraction.m_scaleReciprocal; + const float gridSize = gridSnapParams.m_gridSize; + const bool snapping = gridSnapParams.m_gridSnap; Action action; action.m_fixed = fixed; action.m_start.m_localPosition = startInternal.m_localPosition; - action.m_start.m_snapOffset = startInternal.m_snapOffset; action.m_start.m_localHitPosition = startInternal.m_localHitPosition; action.m_current.m_localOffset = snapping - ? unsnappedOffset + - CalculateSnappedOffset(unsnappedOffset, axis1, gridSize * scaleRecip * nonUniformScaleRecip.Dot(axis1)) + - CalculateSnappedOffset(unsnappedOffset, axis2, gridSize * scaleRecip * nonUniformScaleRecip.Dot(axis2)) + ? CalculateSnappedAmount(unsnappedOffset, axis1, gridSize * scaleRecip * nonUniformScaleRecip.Dot(fixed.m_axis1)) + + CalculateSnappedAmount(unsnappedOffset, axis2, gridSize * scaleRecip * nonUniformScaleRecip.Dot(fixed.m_axis2)) : unsnappedOffset; // record what modifier keys are held during this action @@ -141,18 +125,17 @@ namespace AzToolsFramework { const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); - const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); - m_startInternal = CalculateManipulationDataStart( m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction, rayIntersectionDistance); if (m_onLeftMouseDownCallback) { + const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); + m_onLeftMouseDownCallback(CalculateManipulationDataAction( m_fixed, m_startInternal, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + gridSnapParams, interaction)); } } @@ -164,8 +147,7 @@ namespace AzToolsFramework m_onMouseMoveCallback(CalculateManipulationDataAction( m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(), - TransformNormalizedScale(GetLocalTransform()), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + TransformNormalizedScale(GetLocalTransform()), gridSnapParams, interaction)); } } @@ -177,8 +159,7 @@ namespace AzToolsFramework m_onLeftMouseUpCallback(CalculateManipulationDataAction( m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(), - TransformNormalizedScale(GetLocalTransform()), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + TransformNormalizedScale(GetLocalTransform()), gridSnapParams, interaction)); } } @@ -195,8 +176,7 @@ namespace AzToolsFramework const GridSnapParameters gridSnapParams = GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId); const auto action = CalculateManipulationDataAction( m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(), - TransformNormalizedScale(GetLocalTransform()), - GridSnapAction(gridSnapParams, mouseInteraction.m_keyboardModifiers.Alt()), mouseInteraction); + TransformNormalizedScale(GetLocalTransform()), gridSnapParams, mouseInteraction); // display the exact hit (ray intersection) of the mouse pick on the manipulator DrawTransformAxes( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h index 7a3b2a18a9..154ed4c7d6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h @@ -21,7 +21,7 @@ namespace AzToolsFramework { class ManipulatorView; - struct GridSnapAction; + struct GridSnapParameters; /// PlanarManipulator serves as a visual tool for users to modify values /// in two dimension in a plane defined two non-collinear axes in 3D space. @@ -58,7 +58,6 @@ namespace AzToolsFramework { AZ::Vector3 m_localPosition; ///< The current position of the manipulator in local space. AZ::Vector3 m_localHitPosition; ///< The intersection point in local space between the ray and the manipulator when the mouse down event happens. - AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid. }; /// The state of the manipulator during an interaction. @@ -120,7 +119,6 @@ namespace AzToolsFramework { AZ::Vector3 m_localPosition; ///< The starting position of the manipulator in local space. AZ::Vector3 m_localHitPosition; ///< The intersection point in world space between the ray and the manipulator when the mouse down event happens. - AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid. }; Fixed m_fixed; @@ -134,12 +132,11 @@ namespace AzToolsFramework static StartInternal CalculateManipulationDataStart( const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, - const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance); + const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance); static Action CalculateManipulationDataAction( - const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, - const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, - const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction); + const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, const GridSnapParameters& gridSnapParams, + const ViewportInteraction::MouseInteraction& interaction); }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp index 497bcf15d7..51c5406812 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp @@ -37,13 +37,13 @@ namespace AzToolsFramework axisLength, AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor, AzFramework::ViewportColors::ZAxisColor); - auto mouseDownCallback = [this](const LinearManipulator::Action& action) { + auto mouseDownCallback = [this]([[maybe_unused]] const LinearManipulator::Action& action) + { AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne(); - AZ::NonUniformScaleRequestBus::EventResult( nonUniformScale, m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale); - m_initialScale = nonUniformScale + action.m_start.m_scaleSnapOffset; + m_initialScale = nonUniformScale; AZ::NonUniformScaleRequestBus::Event( m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, m_initialScale); @@ -51,29 +51,37 @@ namespace AzToolsFramework m_manipulators->InstallAxisLeftMouseDownCallback(mouseDownCallback); - m_manipulators->InstallAxisMouseMoveCallback([this](const LinearManipulator::Action& action) { - const AZ::Vector3 scaleMultiplier = - (AZ::Vector3::CreateOne() + ((action.LocalScaleOffset() * action.m_start.m_sign) / m_initialScale)); + m_manipulators->InstallAxisMouseMoveCallback( + [this](const LinearManipulator::Action& action) + { + const AZ::Vector3 scaleMultiplier = + (AZ::Vector3::CreateOne() + ((action.LocalScaleOffset() * action.m_start.m_sign) / m_initialScale)); - AZ::NonUniformScaleRequestBus::Event( - m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, - (scaleMultiplier * m_initialScale).GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale))); - }); + AZ::NonUniformScaleRequestBus::Event( + m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, + (scaleMultiplier * m_initialScale) + .GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale))); + }); m_manipulators->InstallUniformLeftMouseDownCallback(mouseDownCallback); - m_manipulators->InstallUniformMouseMoveCallback([this](const LinearManipulator::Action& action) { - const auto sumVectorElements = [](const AZ::Vector3& vec) { return vec.GetX() + vec.GetY() + vec.GetZ(); }; + m_manipulators->InstallUniformMouseMoveCallback( + [this](const LinearManipulator::Action& action) + { + const auto sumVectorElements = [](const AZ::Vector3& vec) + { + return vec.GetX() + vec.GetY() + vec.GetZ(); + }; - const float minScaleMultiplier = AZ::MinTransformScale / m_initialScale.GetMinElement(); - const float maxScaleMultiplier = AZ::MaxTransformScale / m_initialScale.GetMaxElement(); - const float scaleMultiplier = AZ::GetClamp( - 1.0f + sumVectorElements(action.m_start.m_sign * action.LocalScaleOffset() / m_initialScale), minScaleMultiplier, - maxScaleMultiplier); + const float minScaleMultiplier = AZ::MinTransformScale / m_initialScale.GetMinElement(); + const float maxScaleMultiplier = AZ::MaxTransformScale / m_initialScale.GetMaxElement(); + const float scaleMultiplier = AZ::GetClamp( + 1.0f + sumVectorElements(action.m_start.m_sign * action.LocalScaleOffset() / m_initialScale), minScaleMultiplier, + maxScaleMultiplier); - AZ::NonUniformScaleRequestBus::Event( - m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, scaleMultiplier * m_initialScale); - }); + AZ::NonUniformScaleRequestBus::Event( + m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, scaleMultiplier * m_initialScale); + }); } NonUniformScaleComponentMode::~NonUniformScaleComponentMode() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 5acfa5df59..db321d6818 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -423,15 +423,14 @@ namespace AzToolsFramework } } - static void InitializeTranslationLookup( - EntityIdManipulators& entityIdManipulators, const AZ::Vector3& snapOffset) + static void InitializeTranslationLookup(EntityIdManipulators& entityIdManipulators) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); for (auto& entityIdLookup : entityIdManipulators.m_lookups) { entityIdLookup.second.m_initial = - AZ::Transform::CreateTranslation(GetWorldTranslation(entityIdLookup.first) + snapOffset); + AZ::Transform::CreateTranslation(GetWorldTranslation(entityIdLookup.first)); } } @@ -820,7 +819,7 @@ namespace AzToolsFramework // moving with ctrl - setting override pivotOverrideFrame.m_translationOverride = entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - InitializeTranslationLookup(entityIdManipulators, -action.LocalPositionOffset()); + InitializeTranslationLookup(entityIdManipulators); } else { @@ -1277,12 +1276,12 @@ namespace AzToolsFramework // linear translationManipulators->InstallLinearManipulatorMouseDownCallback( - [this, manipulatorEntityIds](const LinearManipulator::Action& action) mutable + [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action) mutable { // important to sort entityIds based on hierarchy order when updating transforms BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); - InitializeTranslationLookup(m_entityIdManipulators, action.m_start.m_positionSnapOffset); + InitializeTranslationLookup(m_entityIdManipulators); m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( @@ -1302,19 +1301,19 @@ namespace AzToolsFramework }); translationManipulators->InstallLinearManipulatorMouseUpCallback( - [this](const LinearManipulator::Action& /*action*/) mutable + [this]([[maybe_unused]] const LinearManipulator::Action& action) mutable { EndRecordManipulatorCommand(); }); // planar translationManipulators->InstallPlanarManipulatorMouseDownCallback( - [this, manipulatorEntityIds](const PlanarManipulator::Action& action) + [this, manipulatorEntityIds]([[maybe_unused]] const PlanarManipulator::Action& action) { // important to sort entityIds based on hierarchy order when updating transforms BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); - InitializeTranslationLookup(m_entityIdManipulators, action.m_start.m_snapOffset); + InitializeTranslationLookup(m_entityIdManipulators); m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( @@ -1340,11 +1339,11 @@ namespace AzToolsFramework // surface translationManipulators->InstallSurfaceManipulatorMouseDownCallback( - [this, manipulatorEntityIds](const SurfaceManipulator::Action& action) + [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action) { BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); - InitializeTranslationLookup(m_entityIdManipulators, action.m_start.m_snapOffset); + InitializeTranslationLookup(m_entityIdManipulators); m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( @@ -3326,26 +3325,16 @@ namespace AzToolsFramework } static void DrawManipulatorGrid( - AzFramework::DebugDisplayRequests& debugDisplay, const EntityIdManipulators& entityIdManipulators, - const float gridSize, const float localSnapping) + AzFramework::DebugDisplayRequests& debugDisplay, const EntityIdManipulators& entityIdManipulators, const float gridSize) { const AZ::Matrix3x3 orientation = AZ::Matrix3x3::CreateFromTransform(entityIdManipulators.m_manipulators->GetLocalTransform()); - const AZ::Vector3 unsnappedTranslation = + const AZ::Vector3 translation = entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - // calculate the offset to snap by to align the manipulator to the grid - // note: only perform this if we are not snapping in local space - const AZ::Vector3 snappedOffset = !localSnapping - ? CalculateSnappedOffset(unsnappedTranslation, orientation.GetBasisX(), gridSize) + - CalculateSnappedOffset(unsnappedTranslation, orientation.GetBasisY(), gridSize) - : AZ::Vector3::CreateZero(); - - const AZ::Vector3 snappedTranslation = unsnappedTranslation + snappedOffset; - DrawSnappingGrid( - debugDisplay, AZ::Transform::CreateFromMatrix3x3AndTranslation(orientation, snappedTranslation), + debugDisplay, AZ::Transform::CreateFromMatrix3x3AndTranslation(orientation, translation), gridSize); } @@ -3484,7 +3473,7 @@ namespace AzToolsFramework const GridSnapParameters gridSnapParams = GridSnapSettings(viewportInfo.m_viewportId); if (gridSnapParams.m_gridSnap && m_entityIdManipulators.m_manipulators) { - DrawManipulatorGrid(debugDisplay, m_entityIdManipulators, gridSnapParams.m_gridSize, modifiers.Alt()); + DrawManipulatorGrid(debugDisplay, m_entityIdManipulators, gridSnapParams.m_gridSize); } } } From b73de269ee5e271b0854b6ce30b54d2c839b1433 Mon Sep 17 00:00:00 2001 From: Aaron Ruiz Mora Date: Fri, 4 Jun 2021 15:24:22 +0100 Subject: [PATCH 41/45] Use '' instead of 'Default' in Material Selection widget. (#1140) --- Gems/PhysX/Code/Editor/MaterialIdWidget.cpp | 28 +++++++++++---------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp b/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp index 9ec438101a..44787ddd20 100644 --- a/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp +++ b/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp @@ -19,6 +19,8 @@ namespace PhysX { namespace Editor { + static const char* const DefaultPhysicsMaterialLabel = ""; + AZ::u32 MaterialIdWidget::GetHandlerName() const { return Physics::Edit::MaterialIdSelector; @@ -72,8 +74,7 @@ namespace PhysX auto lockToDefault = [gui]() { - static const char* defaultLabel = "Default"; - gui->addItem(defaultLabel); + gui->addItem(DefaultPhysicsMaterialLabel); gui->setCurrentIndex(0); return false; }; @@ -83,30 +84,31 @@ namespace PhysX return lockToDefault(); } - auto materialAsset = AZ::Data::AssetManager::Instance().GetAsset(m_materialLibraryId, AZ::Data::AssetLoadBehavior::Default); - materialAsset.BlockUntilLoadComplete(); + auto materialLibraryAsset = AZ::Data::AssetManager::Instance().GetAsset(m_materialLibraryId, AZ::Data::AssetLoadBehavior::Default); + materialLibraryAsset.BlockUntilLoadComplete(); - if (materialAsset.Get() == nullptr) + if (materialLibraryAsset.Get() == nullptr) { return lockToDefault(); } - const auto& materialsData = materialAsset.Get()->GetMaterialsData(); + const auto& materials = materialLibraryAsset.Get()->GetMaterialsData(); - if (materialsData.size() == 0) + if (materials.empty()) { return lockToDefault(); } - m_libraryIds.reserve(materialsData.size()); + m_libraryIds.reserve(materials.size() + 1); // Plus one to reserve the first element for default physics material + // Add default physics material first m_libraryIds.push_back(Physics::MaterialId()); - gui->addItem("Default"); + gui->addItem(DefaultPhysicsMaterialLabel); - for (const auto& materialData : materialAsset.Get()->GetMaterialsData()) + for (const auto& material : materials) { - gui->addItem(materialData.m_configuration.m_surfaceType.c_str()); - m_libraryIds.push_back(materialData.m_id); + gui->addItem(material.m_configuration.m_surfaceType.c_str()); + m_libraryIds.push_back(material.m_id); } gui->setCurrentIndex(GetIndexForId(instance)); @@ -116,7 +118,7 @@ namespace PhysX Physics::MaterialId MaterialIdWidget::GetIdForIndex(size_t index) { - if (m_libraryIds.size() <= index) + if (index >= m_libraryIds.size()) { return Physics::MaterialId(); } From 5d4226df16a404708b69cb5a46e8aa297adb1767 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Fri, 4 Jun 2021 17:28:43 +0000 Subject: [PATCH 42/45] Get a mesh's morph targets based on the scene graph hierarchy, instead of mesh name (#1128) When building a mesh's morph targets, the exporter has to identify the base mesh in addition to each morph target mesh. Previously this was done by searching the entire scene graph for nodes * of type IBlendShapeData * whose parent's name matches the name of the Atom model This is problematic for a few reasons. The first is that the Atom model's name may have been based on the optimized mesh node. When this happens, the `OptimizedMeshSuffix` that is used in the Scene Graph node's name is stripped off of the Atom model's name. The result is that the *unoptimized* mesh is used as the base mesh for the blend shapes, instead of the optimized blend shape. This of course results in disaster, since the optimizer reorders the vertices, and the base mesh will not match the optimized one. The second is that it is not really necessary to do the search based on the node name at all. All of a mesh's blend shapes are child nodes of the base IMeshData node. With this change, the base mesh is located based on the node data pointer, and all of its child IBlendShapeData nodes are added to the set of blend shapes to process. This way, the Atom model's name isn't involved in the lookup. --- .../Model/MorphTargetExporter.cpp | 83 ++++++++----------- .../RPI.Builders/Model/MorphTargetExporter.h | 5 +- 2 files changed, 36 insertions(+), 52 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp index 3d0cbca8e6..f14d73a9cf 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp @@ -14,9 +14,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -27,62 +29,42 @@ namespace AZ::RPI AZStd::unordered_map MorphTargetExporter::GetBlendShapeInfos( const Containers::Scene& scene, - const AZStd::optional& filterMeshName) const + const MeshData* meshData) const { const Containers::SceneGraph& sceneGraph = scene.GetGraph(); - const auto contentStorage = sceneGraph.GetContentStorage(); - const auto nameStorage = sceneGraph.GetNameStorage(); + + const auto foundBaseMeshIter = AZStd::find_if(sceneGraph.GetContentStorage().cbegin(), sceneGraph.GetContentStorage().cend(), [meshData](const auto& nodeData) + { + return nodeData.get() == meshData; + }); + if (foundBaseMeshIter == sceneGraph.GetContentStorage().cend()) + { + return {}; + } + + const auto baseMeshNodeIndex = sceneGraph.ConvertToNodeIndex(foundBaseMeshIter); + + const auto childBlendShapeDatas = Containers::MakeDerivedFilterView( + Containers::Views::MakeSceneGraphChildView(sceneGraph, baseMeshNodeIndex, sceneGraph.GetContentStorage().cbegin(), true) + ); AZStd::unordered_map result; - - const auto keyValueView = Containers::Views::MakePairView(nameStorage, contentStorage); - const auto filteredView = Containers::Views::MakeFilterView(keyValueView, Containers::DerivedTypeFilter()); - for (const auto& [name, object] : filteredView) + for (auto it = childBlendShapeDatas.cbegin(); it != childBlendShapeDatas.cend(); ++it) { - const Containers::SceneGraph::NodeIndex sceneNodeIndex = sceneGraph.Find(name.GetPath()); + const Containers::SceneGraph::NodeIndex blendShapeNodeIndex = sceneGraph.ConvertToNodeIndex(it.GetBaseIterator().GetBaseIterator().GetHierarchyIterator()); AZStd::set types; - Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, types, scene, sceneNodeIndex); - if (types.find(Events::GraphMetaInfo::GetIgnoreVirtualType()) == types.end()) + Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, types, scene, blendShapeNodeIndex); + if (!types.contains(Events::GraphMetaInfo::GetIgnoreVirtualType())) { - const char* sceneNodePath = name.GetPath(); - const Containers::SceneGraph::NodeIndex nodeIndex = sceneGraph.Find(sceneNodePath); - if (nodeIndex.IsValid()) - { - const AZStd::string meshNodeName = SourceBlendShapeInfo::GetMeshNodeName(sceneGraph, nodeIndex); - if (!filterMeshName.has_value() || - (filterMeshName.has_value() && filterMeshName.value() == meshNodeName)) - { - const AZStd::string blendShapeName = sceneGraph.GetNodeName(nodeIndex).GetName(); - SourceBlendShapeInfo& blendShapeInfo = result[blendShapeName]; - blendShapeInfo.m_sceneNodeIndices.push_back(nodeIndex); - } - } - else - { - AZ_Warning(ModelAssetBuilderComponent::s_builderName, false, "Cannot retrieve scene graph index for blend shape node with path %s.", sceneNodePath); - } + const AZStd::string blendShapeName{sceneGraph.GetNodeName(blendShapeNodeIndex).GetName(), sceneGraph.GetNodeName(blendShapeNodeIndex).GetNameLength()}; + result[blendShapeName].m_sceneNodeIndices.emplace_back(blendShapeNodeIndex); } } return result; } - AZStd::string MorphTargetExporter::SourceBlendShapeInfo::GetMeshNodeName(const Containers::SceneGraph& sceneGraph, - const Containers::SceneGraph::NodeIndex& sceneNodeIndex) - { - const auto* blendShapeData = - azrtti_cast(sceneGraph.GetNodeContent(sceneNodeIndex).get()); - AZ_Assert(blendShapeData, "Cannot get mesh node name from scene node. Node is expected to be a blend shape."); - if (blendShapeData) - { - Containers::SceneGraph::NodeIndex morphMeshParentIndex = sceneGraph.GetNodeParent(sceneNodeIndex); - return sceneGraph.GetNodeName(morphMeshParentIndex).GetName(); - } - - return {}; - } - void MorphTargetExporter::ProduceMorphTargets(const Containers::Scene& scene, uint32_t vertexOffset, const ModelAssetBuilderComponent::SourceMeshContent& sourceMesh, @@ -92,9 +74,14 @@ namespace AZ::RPI { const Containers::SceneGraph& sceneGraph = scene.GetGraph(); +#if defined(AZ_ENABLE_TRACING) + const auto baseMeshIt = AZStd::find(sceneGraph.GetContentStorage().cbegin(), sceneGraph.GetContentStorage().cend(), sourceMesh.m_meshData); + const Containers::SceneGraph::NodeIndex baseMeshIndex = sceneGraph.ConvertToNodeIndex(baseMeshIt); + const AZStd::string_view baseMeshName{sceneGraph.GetNodeName(baseMeshIndex).GetName(), sceneGraph.GetNodeName(baseMeshIndex).GetNameLength()}; +#endif + // Get the blend shapes for the given mesh - const AZStd::string_view meshName = sourceMesh.m_name.GetStringView(); - AZStd::unordered_map blendShapeInfos = GetBlendShapeInfos(scene, meshName); + AZStd::unordered_map blendShapeInfos = GetBlendShapeInfos(scene, sourceMesh.m_meshData.get()); for (const auto& iter : blendShapeInfos) { @@ -109,12 +96,12 @@ namespace AZ::RPI { #if defined(AZ_ENABLE_TRACING) const Containers::SceneGraph::NodeIndex morphMeshParentIndex = sceneGraph.GetNodeParent(sceneNodeIndex); - const char* meshNodeName = sceneGraph.GetNodeName(morphMeshParentIndex).GetName(); + const AZStd::string_view sourceMeshName{sceneGraph.GetNodeName(morphMeshParentIndex).GetName(), sceneGraph.GetNodeName(morphMeshParentIndex).GetNameLength()}; #endif - AZ_Assert(AZ::StringFunc::Equal(sourceMesh.m_name.GetCStr(), meshNodeName, /*bCaseSensitive=*/true), - "Scene graph mesh node (%s) has a different name than the product mesh (%s).", - meshNodeName, sourceMesh.m_name.GetCStr()); + AZ_Assert(AZ::StringFunc::Equal(baseMeshName, sourceMeshName, /*bCaseSensitive=*/true), + "Scene graph mesh node (%.*s) has a different name than the product mesh (%.*s).", + AZ_STRING_ARG(sourceMeshName), AZ_STRING_ARG(baseMeshName)); const DataTypes::MatrixType globalTransform = Utilities::BuildWorldTransform(sceneGraph, sceneNodeIndex); BuildMorphTargetMesh(vertexOffset, sourceMesh, productMesh, metaAssetCreator, blendShapeName, blendShapeData, globalTransform, coordSysConverter, scene.GetSourceFilename()); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h index 4845d7d1da..32f9e2e508 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h @@ -39,12 +39,9 @@ namespace AZ struct SourceBlendShapeInfo { AZStd::vector m_sceneNodeIndices; - - static AZStd::string GetMeshNodeName(const AZ::SceneAPI::Containers::SceneGraph& sceneGraph, - const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& sceneNodeIndex); }; //! Retrieve all scene graph nodes per blend shape for all available blend shapes. - AZStd::unordered_map GetBlendShapeInfos(const AZ::SceneAPI::Containers::Scene& scene, const AZStd::optional& filterMeshName = AZStd::nullopt) const; + AZStd::unordered_map GetBlendShapeInfos(const AZ::SceneAPI::Containers::Scene& scene, const MeshData* meshData) const; //! Calculate position delta tolerance that is used to indicate whether a given vertex is part of the sparse set of morphed vertices //! or if it will be skipped and optimized out due to a hardly visible or no movement at all. From dcdd63966ed43ec80f56aca75c4ba9a80fcc201a Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Fri, 4 Jun 2021 10:28:56 -0700 Subject: [PATCH 43/45] ATOM-15658 Better option of CreateCommonBuffer requires unique buffer name (#1133) * ATOM-15658 Better option of CreateCommonBuffer requires unique buffer name - Change the CreateCommonBuffer function to not require an unique name by default. - Remove the code for generating unique buffer names. - Add buffer name to BufferAsset so it can be used for device object name instead of using asset file name. - Change RPI::Buffer to use BufferName_AssetUuid as attachment id. --- .../Source/CoreLights/LightCullingPass.cpp | 7 +--- .../Source/CoreLights/LightCullingRemap.cpp | 7 +--- .../Common/Code/Source/Math/MathFilter.cpp | 1 + .../ExposureControlSettings.cpp | 11 +----- .../ExposureControl/ExposureControlSettings.h | 4 +- .../DepthOfFieldReadBackFocusDepthPass.cpp | 3 +- .../ExposureControlRenderProxy.cpp | 1 + .../PostProcessing/EyeAdaptationPass.cpp | 6 +-- .../LuminanceHistogramGeneratorPass.cpp | 7 +--- .../RayTracing/RayTracingFeatureProcessor.cpp | 8 +--- .../Source/SkyBox/SkyBoxFeatureProcessor.cpp | 2 +- .../TransformServiceFeatureProcessor.cpp | 6 +-- .../Code/Source/Utils/GpuBufferHandler.cpp | 4 +- .../Include/Atom/RPI.Public/Buffer/Buffer.h | 2 + .../Atom/RPI.Public/Buffer/BufferSystem.h | 2 +- .../RPI.Public/Buffer/BufferSystemInterface.h | 5 ++- .../Atom/RPI.Reflect/Buffer/BufferAsset.h | 4 ++ .../Model/ModelAssetBuilderComponent.cpp | 2 +- .../Code/Source/RPI.Public/Buffer/Buffer.cpp | 17 ++++++--- .../Source/RPI.Public/Buffer/BufferSystem.cpp | 27 ++++++++----- .../DynamicDraw/DynamicBufferAllocator.cpp | 2 +- .../Source/RPI.Reflect/Buffer/BufferAsset.cpp | 8 +++- .../RPI.Reflect/Buffer/BufferAssetCreator.cpp | 5 ++- .../RPI/Code/Tests/Buffer/BufferTests.cpp | 38 +++++++++++++++---- .../EMotionFXAtom/Code/Source/ActorAsset.cpp | 2 +- 25 files changed, 104 insertions(+), 77 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp index 987ed299b3..a9b43ef1e7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp @@ -311,14 +311,9 @@ namespace AZ { auto tileBufferResolution = GetTileDataBufferResolution(); - // generate a UUID for the buffer name to keep it unique when there are multiple render pipelines - AZ::Uuid uuid = AZ::Uuid::CreateRandom(); - AZStd::string uuidString; - uuid.ToString(uuidString); - RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; - desc.m_bufferName = AZStd::string::format("LightList_%s", uuidString.c_str()); + desc.m_bufferName = "LightList"; desc.m_elementSize = sizeof(uint32_t); desc.m_byteCount = tileBufferResolution.m_width * tileBufferResolution.m_height * 256 * sizeof(uint32_t); m_lightList = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp index 42882cec6e..26e4ed9f6e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp @@ -118,14 +118,9 @@ namespace AZ void LightCullingRemap::CreateRemappedLightListBuffer() { - // generate a UUID for the buffer name to keep it unique when there are multiple render pipelines - AZ::Uuid uuid = AZ::Uuid::CreateRandom(); - AZStd::string uuidString; - uuid.ToString(uuidString); - RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; - desc.m_bufferName = AZStd::string::format("LightListRemapped_%s", uuidString.c_str()); + desc.m_bufferName = "LightListRemapped"; desc.m_elementSize = RHI::GetFormatSize(LightListRemappedFormat); desc.m_byteCount = m_tileDim.m_width * m_tileDim.m_height * NumBins * MaxLightsPerTile * desc.m_elementSize; m_lightListRemapped = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); diff --git a/Gems/Atom/Feature/Common/Code/Source/Math/MathFilter.cpp b/Gems/Atom/Feature/Common/Code/Source/Math/MathFilter.cpp index 8190c3af98..cb6f3e3522 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Math/MathFilter.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Math/MathFilter.cpp @@ -74,6 +74,7 @@ namespace AZ desc.m_elementFormat = filters.front()->GetElementFormat(); desc.m_byteCount = totalElementCount * elementSize; desc.m_bufferData = data.data(); + desc.m_isUniqueName = true; auto buffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp index 056f7b7da4..288dd54e2b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp @@ -100,16 +100,9 @@ namespace AZ bool ExposureControlSettings::InitCommonBuffer() { - // generate a UUID for the buffer name to keep it unique - AZ::Uuid uuid = AZ::Uuid::CreateRandom(); - AZStd::string uuidString; - uuid.ToString(uuidString); - - AZStd::string bufferName = AZStd::string::format("%s_%s", ExposureControlBufferBaseName, uuidString.c_str()); - RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::Constant; - desc.m_bufferName = bufferName; + desc.m_bufferName = ExposureControlBufferName; desc.m_byteCount = sizeof(ShaderParameters); desc.m_elementSize = sizeof(ShaderParameters); @@ -117,7 +110,7 @@ namespace AZ if (!m_buffer) { - AZ_Assert(false, "Failed to create the RPI::Buffer[%s] which is used for the exposure control feature.", bufferName.c_str()); + AZ_Assert(false, "Failed to create the RPI::Buffer[%s] which is used for the exposure control feature.", desc.m_bufferName.c_str()); return false; } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.h b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.h index 8344d6aa09..bfb4237b96 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.h @@ -28,8 +28,8 @@ namespace AZ { class PostProcessSettings; - // Base name of the buffer used for the exposure control feature. Usually distinct identifier will be added to this name for each exposure control settings. - static const char* const ExposureControlBufferBaseName = "ExposureControlBuffer"; + // Name of the buffer used for the exposure control feature + static const char* const ExposureControlBufferName = "ExposureControlBuffer"; // The post process sub-settings class for the exposure control feature class ExposureControlSettings final diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp index abd916fcc9..c355b7c8a7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp @@ -47,9 +47,8 @@ namespace AZ m_getDepthPass = static_cast(pass.get()); // Create buffer for read back focus depth. We append static counter to avoid name conflicts. - AZStd::string bufferName = AZStd::string::format("DepthOfFieldReadBackAutoFocusDepthBuffer_%d", s_bufferInstance++); RPI::CommonBufferDescriptor desc; - desc.m_bufferName = bufferName; + desc.m_bufferName = "DepthOfFieldReadBackAutoFocusDepthBuffer"; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; desc.m_byteCount = sizeof(float); desc.m_elementSize = aznumeric_cast(desc.m_byteCount); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/ExposureControlRenderProxy.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/ExposureControlRenderProxy.cpp index eb7a3b527f..c70d56aa90 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/ExposureControlRenderProxy.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/ExposureControlRenderProxy.cpp @@ -71,6 +71,7 @@ namespace AZ desc.m_bufferName = bufferName; desc.m_byteCount = sizeof(ShaderParameters); desc.m_elementSize = sizeof(ShaderParameters); + desc.m_isUniqueName = true; m_buffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp index e7d4c47f02..bf293fd3d2 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp @@ -34,7 +34,7 @@ namespace AZ { namespace Render { - static const char* const EyeAdaptationBufferBaseName = "EyeAdaptationBuffer"; + static const char* const EyeAdaptationBufferName = "EyeAdaptationBuffer"; RPI::Ptr EyeAdaptationPass::Create(const RPI::PassDescriptor& descriptor) { @@ -49,12 +49,10 @@ namespace AZ void EyeAdaptationPass::InitBuffer() { - AZStd::string bufferName = AZStd::string::format("%s_%p", EyeAdaptationBufferBaseName, this); - ExposureCalculationData defaultData; RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; - desc.m_bufferName = bufferName; + desc.m_bufferName = EyeAdaptationBufferName; desc.m_byteCount = sizeof(ExposureCalculationData); desc.m_elementSize = aznumeric_cast(desc.m_byteCount); desc.m_bufferData = &defaultData; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp index 758c21bc4e..715ebf2945 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp @@ -62,14 +62,9 @@ namespace AZ void LuminanceHistogramGeneratorPass::CreateHistogramBuffer() { - // generate a UUID for the buffer name to keep it unique when there are multiple render pipelines - AZ::Uuid uuid = AZ::Uuid::CreateRandom(); - AZStd::string uuidString; - uuid.ToString(uuidString); - RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; - desc.m_bufferName = AZStd::string::format("LuminanceHistogramBuffer_%s", uuidString.c_str()); + desc.m_bufferName = "LuminanceHistogramBuffer"; desc.m_elementSize = sizeof(uint32_t); desc.m_byteCount = NumHistogramBins * sizeof(uint32_t); desc.m_elementFormat = RHI::Format::R32_UINT; diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp index 10c7c2d378..2db396e36d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp @@ -210,12 +210,10 @@ namespace AZ if (m_meshInfoBuffer == nullptr) { - AZStd::string uuidString = AZ::Uuid::CreateRandom().ToString(); - // allocate the MeshInfo structured buffer RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly; - desc.m_bufferName = AZStd::string::format("RayTracingMeshInfo_%s", uuidString.c_str()); + desc.m_bufferName = "RayTracingMeshInfo"; desc.m_byteCount = newMeshByteCount; desc.m_elementSize = sizeof(MeshInfo); m_meshInfoBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); @@ -283,12 +281,10 @@ namespace AZ if (m_materialInfoBuffer == nullptr) { - AZStd::string uuidString = AZ::Uuid::CreateRandom().ToString(); - // allocate the MaterialInfo structured buffer RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly; - desc.m_bufferName = AZStd::string::format("RayTracingMaterialInfo_%s", uuidString.c_str()); + desc.m_bufferName = "RayTracingMaterialInfo"; desc.m_byteCount = newMaterialByteCount; desc.m_elementSize = sizeof(MaterialInfo); m_materialInfoBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); diff --git a/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp index 058e243fb7..4a3586a799 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp @@ -193,7 +193,7 @@ namespace AZ RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::Constant; - desc.m_bufferName = AZStd::string::format("SkyboxBuffer_%p", this); + desc.m_bufferName = "SkyboxBuffer"; desc.m_byteCount = byteCount; desc.m_elementSize = byteCount; desc.m_bufferData = &m_physicalSkyData; diff --git a/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp index fb73d0f416..074b09e35d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp @@ -89,13 +89,13 @@ namespace AZ // Create the transform buffer, grow by powers of two RPI::CommonBufferDescriptor desc2; desc2.m_poolType = RPI::CommonBufferPoolType::ReadOnly; - desc2.m_bufferName = AZStd::string::format("'m_objectToWorldBuffer_%" PRIXPTR, reinterpret_cast(this)); + desc2.m_bufferName = "m_objectToWorldBuffer"; desc2.m_byteCount = byteCount; desc2.m_elementSize = elementSize; m_objectToWorldBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc2); - desc2.m_bufferName = AZStd::string::format("'m_objectToWorldHistoryBuffer_%p", this); + desc2.m_bufferName = "m_objectToWorldHistoryBuffer"; m_objectToWorldHistoryBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc2); } else @@ -119,7 +119,7 @@ namespace AZ // Create the normal buffer, grow by powers of two RPI::CommonBufferDescriptor desc2; desc2.m_poolType = RPI::CommonBufferPoolType::ReadOnly; - desc2.m_bufferName = AZStd::string::format("'m_objectToWorldInverseTransposeBuffer_%" PRIXPTR, reinterpret_cast(this)); + desc2.m_bufferName = "m_objectToWorldInverseTransposeBuffer"; desc2.m_byteCount = byteCount; desc2.m_elementSize = elementSize; diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/GpuBufferHandler.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/GpuBufferHandler.cpp index 13a151f8ac..db78247251 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/GpuBufferHandler.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/GpuBufferHandler.cpp @@ -40,13 +40,11 @@ namespace AZ if (m_bufferIndex.IsValid()) { - AZStd::string bufferName = AZStd::string::format("%s_%" PRIXPTR, descriptor.m_bufferName.c_str(), reinterpret_cast(this)); - uint32_t byteCount = RHI::NextPowerOfTwo(GetMax(BufferMinSize, m_elementCount * m_elementSize)); RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly; - desc.m_bufferName = bufferName; + desc.m_bufferName = descriptor.m_bufferName; desc.m_byteCount = byteCount; desc.m_elementSize = descriptor.m_elementSize; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/Buffer.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/Buffer.h index 3fef502e92..df24c7591b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/Buffer.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/Buffer.h @@ -112,6 +112,8 @@ namespace AZ AZStd::mutex m_pendingUploadMutex; RHI::BufferViewDescriptor m_bufferViewDescriptor; + + RHI::AttachmentId m_attachmentId; }; template diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h index c4b6aa74b4..9f5b150752 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h @@ -35,7 +35,7 @@ namespace AZ // BufferSystemInterface overrides... RHI::Ptr GetCommonBufferPool(CommonBufferPoolType poolType) override; Data::Instance CreateBufferFromCommonPool(const CommonBufferDescriptor& descriptor) override; - Data::Instance FindCommonBuffer(AZStd::string_view bufferName) override; + Data::Instance FindCommonBuffer(AZStd::string_view uniqueBufferName) override; void Init(); void Shutdown(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystemInterface.h index 1469eed060..39b4b09691 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystemInterface.h @@ -53,6 +53,9 @@ namespace AZ RHI::Format m_elementFormat = RHI::Format::Unknown; // CreateBufferFromCommonPool(const CommonBufferDescriptor& descriptor) = 0; //! Find a buffer by name. The buffer has to be created by CreateBufferFromCommonPool function - virtual Data::Instance FindCommonBuffer(AZStd::string_view bufferName) = 0; + virtual Data::Instance FindCommonBuffer(AZStd::string_view uniqueBufferName) = 0; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h index d8a6fbb44d..4776933de6 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h @@ -60,11 +60,15 @@ namespace AZ const Data::Asset& GetPoolAsset() const; CommonBufferPoolType GetCommonPoolType() const; + + const AZStd::string& GetName() const; private: // Called by asset creators to assign the asset to a ready state. void SetReady(); + AZStd::string m_name; + AZStd::vector m_buffer; RHI::BufferDescriptor m_bufferDescriptor; 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 ea2bdd0d83..f559a0aba6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp @@ -114,7 +114,7 @@ namespace AZ if (auto* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(26); // [ATOM-14992] + ->Version(27); // [ATOM-15658] } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp index 470b66c28e..81f02b7435 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp @@ -32,10 +32,6 @@ namespace AZ auto buffer = Data::InstanceDatabase::Instance().FindOrCreate( Data::InstanceId::CreateFromAssetId(bufferAsset.GetId()), bufferAsset); - if (buffer && buffer->m_rhiBuffer) - { - buffer->m_rhiBuffer->SetName(Name(bufferAsset.GetHint())); - } return buffer; } @@ -170,6 +166,16 @@ namespace AZ return resultCode; } } + + m_rhiBuffer->SetName(Name(bufferAsset.GetName())); + + // Only generate buffer's attachment id if the buffer is writable + if (RHI::CheckBitsAny(m_rhiBuffer->GetDescriptor().m_bindFlags, + RHI::BufferBindFlags::ShaderWrite | RHI::BufferBindFlags::CopyWrite | RHI::BufferBindFlags::DynamicInputAssembly)) + { + // attachment id = bufferName_bufferInstanceId + m_attachmentId = Name(bufferAsset.GetName() + "_" + bufferAsset.GetId().m_guid.ToString(false, false)); + } return RHI::ResultCode::Success; } @@ -312,7 +318,8 @@ namespace AZ const RHI::AttachmentId& Buffer::GetAttachmentId() const { - return m_rhiBuffer->GetName(); + AZ_Assert(!m_attachmentId.GetStringView().empty(), "Read-only buffer doesn't need attachment id"); + return m_attachmentId; } const RHI::BufferViewDescriptor& Buffer::GetBufferViewDescriptor() const diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp index 9a9254b0d6..c4b4b28d44 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp @@ -152,15 +152,22 @@ namespace AZ } Data::Instance BufferSystem::CreateBufferFromCommonPool(const CommonBufferDescriptor& descriptor) - { - Uuid bufferId = Uuid::CreateName(descriptor.m_bufferName.c_str()); - - // Report error if there is a buffer with same name. - // Note: this shouldn't return the existing buffer because users are expecting a newly created buffer. - if (Data::InstanceDatabase::Instance().Find(Data::InstanceId(bufferId))) + { + Uuid bufferId; + if (descriptor.m_isUniqueName) { - AZ_Error("BufferSystem", false, "Buffer with same name '%s' already exist", descriptor.m_bufferName.c_str()); - return nullptr; + bufferId = Uuid::CreateName(descriptor.m_bufferName.c_str()); + // Report error if there is a buffer with same name. + // Note: this shouldn't return the existing buffer because users are expecting a newly created buffer. + if (Data::InstanceDatabase::Instance().Find(Data::InstanceId(bufferId))) + { + AZ_Error("BufferSystem", false, "Buffer with same name '%s' already exist", descriptor.m_bufferName.c_str()); + return nullptr; + } + } + else + { + bufferId = Uuid::CreateRandom(); } RHI::Ptr bufferPool = GetCommonBufferPool(descriptor.m_poolType); @@ -207,9 +214,9 @@ namespace AZ return nullptr; } - Data::Instance BufferSystem::FindCommonBuffer(AZStd::string_view bufferName) + Data::Instance BufferSystem::FindCommonBuffer(AZStd::string_view uniqueBufferName) { - Uuid bufferId = Uuid::CreateName(bufferName.data()); + Uuid bufferId = Uuid::CreateName(uniqueBufferName.data()); return Data::InstanceDatabase::Instance().Find(Data::InstanceId(bufferId)); } } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicBufferAllocator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicBufferAllocator.cpp index e79aa2e1bb..627b1e9912 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicBufferAllocator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicBufferAllocator.cpp @@ -30,7 +30,7 @@ namespace AZ // Create the ring buffer from common pool RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::DynamicInputAssembly; - desc.m_bufferName = AZStd::string::format("DyanmicBufferRing_%p", this); + desc.m_bufferName = "DyanmicBufferRing"; desc.m_elementSize = 1; desc.m_byteCount = ringBufferSize; m_ringBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); 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 6f9d3a9d64..69444ae466 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAsset.cpp @@ -30,7 +30,8 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(1) + ->Version(2) + ->Field("Name", &BufferAsset::m_name) ->Field("Buffer", &BufferAsset::m_buffer) ->Field("BufferDescriptor", &BufferAsset::m_bufferDescriptor) ->Field("BufferViewDescriptor", &BufferAsset::m_bufferViewDescriptor) @@ -80,5 +81,10 @@ namespace AZ { return m_poolType; } + + const AZStd::string& BufferAsset::GetName() const + { + return m_name; + } } //namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp index 486be9860e..4bd1b53f57 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp @@ -152,7 +152,10 @@ namespace AZ void BufferAssetCreator::SetBufferName(AZStd::string_view name) { - m_asset.SetHint(name); + if (ValidateIsReady()) + { + m_asset->m_name = name; + } } bool BufferAssetCreator::Clone(const Data::Asset& sourceAsset, Data::Asset& clonedResult, Data::AssetId& inOutLastCreatedAssetId) diff --git a/Gems/Atom/RPI/Code/Tests/Buffer/BufferTests.cpp b/Gems/Atom/RPI/Code/Tests/Buffer/BufferTests.cpp index df3af5f0d2..261b57a568 100644 --- a/Gems/Atom/RPI/Code/Tests/Buffer/BufferTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Buffer/BufferTests.cpp @@ -474,6 +474,7 @@ namespace UnitTest desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly; desc.m_bufferName = "Buffer1"; desc.m_byteCount = bufferInfo.m_bufferDescriptor.m_byteCount; + desc.m_isUniqueName = true; Data::Instance bufferInst = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); // buffer created @@ -488,8 +489,33 @@ namespace UnitTest EXPECT_EQ(bufferFound2.get(), nullptr); } - // Failed if creates a buffer with duplicated name with existing buffer - TEST_F(BufferTests, BufferSystem_CreateDuplicatedNamedBuffer_Fail) + // Failed if creates a buffe which has a same name with existing buffer + // and has m_isUniqueName is enabled + TEST_F(BufferTests, BufferSystem_CreateDuplicatedNamedBufferEnableUniqueName_Fail) + { + using namespace AZ; + + ExpectedBuffer bufferInfo = CreateValidBuffer(); + + RPI::CommonBufferDescriptor desc; + desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly; + desc.m_bufferName = "Buffer1"; + desc.m_byteCount = bufferInfo.m_bufferDescriptor.m_byteCount; + desc.m_isUniqueName = true; + + Data::Instance bufferInst = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); + // buffer created + EXPECT_NE(bufferInst.get(), nullptr); + + AZ_TEST_START_ASSERTTEST; + Data::Instance bufferInst2 = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); + AZ_TEST_STOP_ASSERTTEST(1); + // buffer NOT created + EXPECT_EQ(bufferInst2.get(), nullptr); + } + + // create a buffer which has a same name with existing buffer + TEST_F(BufferTests, BufferSystem_CreateDuplicatedNamedBuffers_Success) { using namespace AZ; @@ -503,12 +529,10 @@ namespace UnitTest Data::Instance bufferInst = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); // buffer created EXPECT_NE(bufferInst.get(), nullptr); - - AZ_TEST_START_ASSERTTEST; + Data::Instance bufferInst2 = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); - AZ_TEST_STOP_ASSERTTEST(1); - // buffer NOT created - EXPECT_EQ(bufferInst2.get(), nullptr); + // buffer created + EXPECT_NE(bufferInst2.get(), nullptr); } // Buffer instance creation unit tests diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp index 8dc7f9387c..9f68a7d12c 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp @@ -595,7 +595,7 @@ namespace AZ // Create a buffer and populate it with the transforms RPI::CommonBufferDescriptor descriptor; descriptor.m_bufferData = boneTransforms.data(); - descriptor.m_bufferName = AZStd::string::format("BoneTransformBuffer_%s_%s", actorInstance->GetActor()->GetName(), Uuid::CreateRandom().ToString().c_str()); + descriptor.m_bufferName = AZStd::string::format("BoneTransformBuffer_%s", actorInstance->GetActor()->GetName()); descriptor.m_byteCount = boneTransforms.size() * sizeof(float); descriptor.m_elementSize = floatsPerBone * sizeof(float); descriptor.m_poolType = RPI::CommonBufferPoolType::ReadOnly; From 76a6df341b0b05eafb53f4977cd706a80a3b2b3d Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 4 Jun 2021 10:51:47 -0700 Subject: [PATCH 44/45] SPEC-2513 Fixes to enable w4457 --- .../UdpTransport/UdpFragmentQueue.cpp | 4 +- Code/Sandbox/Editor/CVarMenu.cpp | 14 ++-- .../Editor/TrackView/TrackViewAnimNode.cpp | 4 +- .../Editor/TrackView/TrackViewTrack.cpp | 6 +- .../Vulkan/Code/Source/RHI/DescriptorSet.cpp | 4 +- .../Window/ShaderManagementConsoleWindow.cpp | 4 +- .../Source/Editor/QATLControlsTreeModel.cpp | 8 +- .../EMotionFX/Rendering/Common/RenderUtil.cpp | 12 +-- .../EMotionFX/Source/MultiThreadScheduler.cpp | 4 +- .../PropertyWidgets/MotionDataHandler.cpp | 6 +- .../StaticLib/GraphCanvas/Styling/Parser.cpp | 80 +++++++++---------- .../GraphCanvas/Utils/GraphUtils.cpp | 6 +- Gems/GraphModel/Code/Source/Model/Graph.cpp | 4 +- .../Editor/Animation/UiAnimViewAnimNode.cpp | 12 +-- .../Code/Editor/Animation/UiAnimViewTrack.cpp | 6 +- .../MicrophoneSystemComponent_Windows.cpp | 22 ++--- .../NetworkEntity/NetworkEntityManager.cpp | 4 +- .../Widgets/NodePalette/NodePaletteModel.cpp | 12 +-- .../View/Windows/ScriptCanvasContextMenus.cpp | 4 +- .../Grammar/AbstractCodeModel.cpp | 10 +-- .../Internal/Nodes/ExpressionNodeBase.cpp | 6 +- .../Code/Source/Core/WhiteBoxToolApi.cpp | 16 ++-- .../Common/MSVC/Configurations_msvc.cmake | 1 - 23 files changed, 124 insertions(+), 125 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpFragmentQueue.cpp b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpFragmentQueue.cpp index 2a90509187..042f19aa70 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpFragmentQueue.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpFragmentQueue.cpp @@ -139,7 +139,7 @@ namespace AzNetworking NetworkOutputSerializer networkSerializer(buffer.GetBuffer(), buffer.GetSize()); { - ISerializer& serializer = networkSerializer; // To get the default typeinfo parameters in ISerializer + ISerializer& networkISerializer = networkSerializer; // To get the default typeinfo parameters in ISerializer // First, serialize out the header if (!header.SerializePacketFlags(networkSerializer)) @@ -148,7 +148,7 @@ namespace AzNetworking return false; } - if (!serializer.Serialize(header, "Header")) + if (!networkISerializer.Serialize(header, "Header")) { AZLOG(NET_FragmentQueue, "Reconstructed fragmented packet failed header serialization"); return false; diff --git a/Code/Sandbox/Editor/CVarMenu.cpp b/Code/Sandbox/Editor/CVarMenu.cpp index f3dd4cf065..bbce0c63fc 100644 --- a/Code/Sandbox/Editor/CVarMenu.cpp +++ b/Code/Sandbox/Editor/CVarMenu.cpp @@ -118,10 +118,10 @@ void CVarMenu::AddUniqueCVarsItem(QString displayName, // Otherwise we could have just used the action's currently checked // state and updated the CVar's value only bool cVarOn = (cVar->GetFVal() == availableCVar.m_onValue); - bool checked = !cVarOn; - SetCVar(cVar, checked ? availableCVar.m_onValue : availableCVar.m_offValue); - action->setChecked(checked); - if (checked) + bool cVarChecked = !cVarOn; + SetCVar(cVar, cVarChecked ? availableCVar.m_onValue : availableCVar.m_offValue); + action->setChecked(cVarChecked); + if (cVarChecked) { // Set the rest of the CVars in the group to their off values SetCVarsToOffValue(availableCVars, availableCVar); @@ -132,9 +132,9 @@ void CVarMenu::AddUniqueCVarsItem(QString displayName, // Initialize the action's checked state based on its associated CVar's current value ICVar* cVar = gEnv->pConsole->GetCVar(availableCVar.m_cVarName.toUtf8().data()); - bool checked = (cVar && cVar->GetFVal() == availableCVar.m_onValue); - action->setChecked(checked); - if (checked) + bool cVarChecked = (cVar && cVar->GetFVal() == availableCVar.m_onValue); + action->setChecked(cVarChecked); + if (cVarChecked) { // Set the rest of the CVars in the group to their off values SetCVarsToOffValue(availableCVars, availableCVar); diff --git a/Code/Sandbox/Editor/TrackView/TrackViewAnimNode.cpp b/Code/Sandbox/Editor/TrackView/TrackViewAnimNode.cpp index 35306b9535..2b4622f5ec 100644 --- a/Code/Sandbox/Editor/TrackView/TrackViewAnimNode.cpp +++ b/Code/Sandbox/Editor/TrackView/TrackViewAnimNode.cpp @@ -205,10 +205,10 @@ CTrackViewAnimNode::CTrackViewAnimNode(IAnimSequence* pSequence, IAnimNode* anim for (int i = 0; i < nodeCount; ++i) { IAnimNode* node = pSequence->GetNode(i); - IAnimNode* pParentNode = node->GetParent(); + IAnimNode* pNodeParentNode = node->GetParent(); // If our node is the parent, then the current node is a child of it - if (animNode == pParentNode) + if (animNode == pNodeParentNode) { CTrackViewAnimNodeFactory animNodeFactory; CTrackViewAnimNode* pNewTVAnimNode = animNodeFactory.BuildAnimNode(pSequence, node, this); diff --git a/Code/Sandbox/Editor/TrackView/TrackViewTrack.cpp b/Code/Sandbox/Editor/TrackView/TrackViewTrack.cpp index 94559921c3..76a836f86c 100644 --- a/Code/Sandbox/Editor/TrackView/TrackViewTrack.cpp +++ b/Code/Sandbox/Editor/TrackView/TrackViewTrack.cpp @@ -68,12 +68,12 @@ CTrackViewTrack::CTrackViewTrack(IAnimTrack* pTrack, CTrackViewAnimNode* pTrackA { // Search for child tracks const unsigned int subTrackCount = m_pAnimTrack->GetSubTrackCount(); - for (unsigned int subTrackIndex = 0; subTrackIndex < subTrackCount; ++subTrackIndex) + for (unsigned int subTrackI = 0; subTrackI < subTrackCount; ++subTrackI) { - IAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackIndex); + IAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackI); CTrackViewTrackFactory trackFactory; - CTrackViewTrack* pNewTVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackIndex); + CTrackViewTrack* pNewTVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackI); m_childNodes.push_back(std::unique_ptr(pNewTVTrack)); } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp index 634f5a51ac..37f1e31542 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp @@ -261,8 +261,8 @@ namespace AZ if (vulkanDescriptor.m_constantDataPool && constantDataSize) { m_constantDataBuffer = Buffer::Create(); - const RHI::BufferDescriptor descriptor(RHI::BufferBindFlags::Constant, constantDataSize); - RHI::BufferInitRequest request(*m_constantDataBuffer, descriptor); + const RHI::BufferDescriptor bufferDescriptor(RHI::BufferBindFlags::Constant, constantDataSize); + RHI::BufferInitRequest request(*m_constantDataBuffer, bufferDescriptor); RHI::ResultCode rhiResult = vulkanDescriptor.m_constantDataPool->InitBuffer(request); if (rhiResult != RHI::ResultCode::Success) { diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp index 6ab297bfc5..08d406884f 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp @@ -510,9 +510,9 @@ namespace ShaderManagementConsole AZStd::vector documentIdsToClose; documentIdsToClose.reserve(m_tabWidget->count()); const AZ::Uuid documentIdToKeepOpen = GetDocumentIdFromTab(tabIndex); - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + for (int tabI = 0; tabI < m_tabWidget->count(); ++tabI) { - const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); + const AZ::Uuid documentId = GetDocumentIdFromTab(tabI); if (documentId != documentIdToKeepOpen) { documentIdsToClose.push_back(documentId); diff --git a/Gems/AudioSystem/Code/Source/Editor/QATLControlsTreeModel.cpp b/Gems/AudioSystem/Code/Source/Editor/QATLControlsTreeModel.cpp index d05f7830a4..32446237a3 100644 --- a/Gems/AudioSystem/Code/Source/Editor/QATLControlsTreeModel.cpp +++ b/Gems/AudioSystem/Code/Source/Editor/QATLControlsTreeModel.cpp @@ -287,9 +287,9 @@ namespace AudioControls QDataStream stream(&encoded, QIODevice::ReadOnly); while (!stream.atEnd()) { - int row, col; + int streamRow, streamCol; QMap roleDataMap; - stream >> row >> col >> roleDataMap; + stream >> streamRow >> streamCol >> roleDataMap; if (!roleDataMap.isEmpty()) { // If dropping a folder, make sure that folder name doesn't already exist where it is being dropped @@ -341,9 +341,9 @@ namespace AudioControls { QByteArray data = mimeData->data(format); QDataStream stream(&data, QIODevice::ReadOnly); - int row, col; + int streamRow, streamCol; QMap roleDataMap; - stream >> row >> col >> roleDataMap; + stream >> streamRow >> streamCol >> roleDataMap; if (!roleDataMap.isEmpty() && roleDataMap[eDR_TYPE] != eIT_FOLDER) { return false; diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp index b2389a3086..90752c7604 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp @@ -1628,18 +1628,18 @@ namespace MCommon } else { - const float screenWidth = static_cast(camera->GetScreenWidth()); - const float screenHeight = static_cast(camera->GetScreenHeight()); + const float cameraScreenWidth = static_cast(camera->GetScreenWidth()); + const float cameraScreenHeight = static_cast(camera->GetScreenHeight()); // find the 4 corners of the frustum AZ::Vector3 corners[4]; const AZ::Matrix4x4 inversedProjectionMatrix = MCore::InvertProjectionMatrix(camera->GetProjectionMatrix()); const AZ::Matrix4x4 inversedViewMatrix = MCore::InvertProjectionMatrix(camera->GetViewMatrix()); - corners[0] = MCore::Unproject(0.0f, 0.0f, screenWidth, screenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); - corners[1] = MCore::Unproject(screenWidth, 0.0f, screenWidth, screenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); - corners[2] = MCore::Unproject(screenWidth, screenHeight, screenWidth, screenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); - corners[3] = MCore::Unproject(0.0f, screenHeight, screenWidth, screenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); + corners[0] = MCore::Unproject(0.0f, 0.0f, cameraScreenWidth, cameraScreenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); + corners[1] = MCore::Unproject(cameraScreenWidth, 0.0f, cameraScreenWidth, cameraScreenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); + corners[2] = MCore::Unproject(cameraScreenWidth, cameraScreenHeight, cameraScreenWidth, cameraScreenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); + corners[3] = MCore::Unproject(0.0f, cameraScreenHeight, cameraScreenWidth, cameraScreenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); // calculate the intersection points with the ground plane and create an AABB around those // if there is no intersection point then use the ray target as point, which is the projection onto the far plane basically diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/MultiThreadScheduler.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/MultiThreadScheduler.cpp index 327f9d27ae..1094ad72a3 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/MultiThreadScheduler.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/MultiThreadScheduler.cpp @@ -319,9 +319,9 @@ namespace EMotionFX step.mDependencies.Clear(false); // calculate the new dependencies for this step - for (ActorInstance* actorInstance : step.mActorInstances) + for (ActorInstance* stepActorInstance : step.mActorInstances) { - AddDependenciesToStep(actorInstance, &step); + AddDependenciesToStep(stepActorInstance, &step); } // assume that there is only one of the same actor instance in the whole schedule diff --git a/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/MotionDataHandler.cpp b/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/MotionDataHandler.cpp index 7597cb888d..6060a81bd0 100644 --- a/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/MotionDataHandler.cpp +++ b/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/MotionDataHandler.cpp @@ -91,10 +91,10 @@ namespace EMotionFX } else { - AZ::Outcome index = factory.FindRegisteredIndexByTypeId(instance); - if (index.IsSuccess()) + AZ::Outcome motionIndex = factory.FindRegisteredIndexByTypeId(instance); + if (motionIndex.IsSuccess()) { - GUI->setCurrentIndex(static_cast(index.GetValue() + 1)); // +1 because we inserted an 'Automatic' one as first entry. + GUI->setCurrentIndex(static_cast(motionIndex.GetValue() + 1)); // +1 because we inserted an 'Automatic' one as first entry. } else { diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp index db07c3ca8e..23d28857e1 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp @@ -725,23 +725,23 @@ namespace GraphCanvas case Attribute::LineColor: case Attribute::StripeColor: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (IsColorValid(value)) + if (IsColorValid(valueStr)) { - style->SetAttribute(attribute, ParseColor(value)); + style->SetAttribute(attribute, ParseColor(valueStr)); } break; } case Attribute::BackgroundImage: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (value.startsWith(QStringLiteral(":/"))) + if (valueStr.startsWith(QStringLiteral(":/"))) { - value = QString("qrc%1").arg(value); + valueStr = QString("qrc%1").arg(valueStr); } - QUrl url(value); + QUrl url(valueStr); if (url.isValid()) { style->SetAttribute(attribute, url); @@ -844,103 +844,103 @@ namespace GraphCanvas case Attribute::BorderStyle: case Attribute::LineStyle: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (IsLineStyleValid(value)) + if (IsLineStyleValid(valueStr)) { - style->SetAttribute(attribute, QVariant::fromValue(ParseLineStyle(value))); + style->SetAttribute(attribute, QVariant::fromValue(ParseLineStyle(valueStr))); } break; } case Attribute::LineCurve: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (IsLineCurveValid(value)) + if (IsLineCurveValid(valueStr)) { - style->SetAttribute(attribute, QVariant::fromValue(ParseLineCurve(value))); + style->SetAttribute(attribute, QVariant::fromValue(ParseLineCurve(valueStr))); } break; } case Attribute::CapStyle: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (IsCapStyleValid(value)) + if (IsCapStyleValid(valueStr)) { - style->SetAttribute(attribute, QVariant::fromValue(ParseCapStyle(value))); + style->SetAttribute(attribute, QVariant::fromValue(ParseCapStyle(valueStr))); } break; } case Attribute::FontFamily: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (QString::compare(value, QLatin1String("default"), Qt::CaseInsensitive) == 0) + if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0) { - value = defaultFontInfo.family(); + valueStr = defaultFontInfo.family(); } else { - QFont font(value); + QFont font(valueStr); QFontInfo info(font); if (!info.exactMatch()) { - qWarning() << "Invalid font-family:" << value; + qWarning() << "Invalid font-family:" << valueStr; } } - style->SetAttribute(attribute, value); + style->SetAttribute(attribute, valueStr); } case Attribute::FontStyle: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (QString::compare(value, QLatin1String("default"), Qt::CaseInsensitive) == 0) + if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0) { style->SetAttribute(attribute, defaultFontInfo.style()); } else { - if (IsFontStyleValid(value)) + if (IsFontStyleValid(valueStr)) { - style->SetAttribute(attribute, ParseFontStyle(value)); + style->SetAttribute(attribute, ParseFontStyle(valueStr)); } } break; } case Attribute::FontWeight: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (QString::compare(value, QLatin1String("default"), Qt::CaseInsensitive) == 0) + if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0) { style->SetAttribute(attribute, defaultFontInfo.weight()); } else { - if (IsFontWeightValid(value)) + if (IsFontWeightValid(valueStr)) { - style->SetAttribute(attribute, ParseFontWeight(value)); + style->SetAttribute(attribute, ParseFontWeight(valueStr)); } } break; } case Attribute::FontVariant: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (QString::compare(value, QLatin1String("default"), Qt::CaseInsensitive) == 0) + if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0) { style->SetAttribute(attribute, defaultFont.capitalization()); } else { - if (IsFontVariantValid(value)) + if (IsFontVariantValid(valueStr)) { - style->SetAttribute(attribute, value); + style->SetAttribute(attribute, valueStr); } } break; @@ -965,23 +965,23 @@ namespace GraphCanvas break; case Attribute::PaletteStyle: { - QString value(member->value.GetString()); - style->SetAttribute(attribute, QVariant::fromValue(ParsePaletteStyle(value))); + QString valueStr(member->value.GetString()); + style->SetAttribute(attribute, QVariant::fromValue(ParsePaletteStyle(valueStr))); break; } case Attribute::PatternTemplate: case Attribute::PatternPalettes: { - QString value(member->value.GetString()); - style->SetAttribute(attribute, value); + QString valueStr(member->value.GetString()); + style->SetAttribute(attribute, valueStr); break; } case Attribute::Steps: { QList stepList; - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - QStringList splitValues = value.split("|"); + QStringList splitValues = valueStr.split("|"); for (QString currentString : splitValues) { diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp index c2574a69f6..16bc3dd86a 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp @@ -1325,12 +1325,12 @@ namespace GraphCanvas AZStd::vector< Endpoint > endpoints; SlotRequestBus::EventResult(endpoints, currentEndpoint.GetSlotId(), &SlotRequests::GetRemappedModelEndpoints); - for (const Endpoint& endpoint : endpoints) + for (const Endpoint& e : endpoints) { // If we haven't already processed the node, add it to our explore set so we can recurse. - if (retVal.count(endpoint) == 0) + if (retVal.count(e) == 0) { - exploreSet.insert(endpoint); + exploreSet.insert(e); } } } diff --git a/Gems/GraphModel/Code/Source/Model/Graph.cpp b/Gems/GraphModel/Code/Source/Model/Graph.cpp index 25ad61db2c..809679e9f6 100644 --- a/Gems/GraphModel/Code/Source/Model/Graph.cpp +++ b/Gems/GraphModel/Code/Source/Model/Graph.cpp @@ -279,8 +279,8 @@ namespace GraphModel m_connections.erase(iter); #if defined(AZ_ENABLE_TRACING) - auto iter = AZStd::find(m_connections.begin(), m_connections.end(), connection); - AZ_Assert(iter == m_connections.end(), "Graph is broken. The same connection object was found multiple times."); + auto iterConnection = AZStd::find(m_connections.begin(), m_connections.end(), connection); + AZ_Assert(iterConnection == m_connections.end(), "Graph is broken. The same connection object was found multiple times."); #endif return true; diff --git a/Gems/LyShine/Code/Editor/Animation/UiAnimViewAnimNode.cpp b/Gems/LyShine/Code/Editor/Animation/UiAnimViewAnimNode.cpp index f99eea5fa2..37629fac37 100644 --- a/Gems/LyShine/Code/Editor/Animation/UiAnimViewAnimNode.cpp +++ b/Gems/LyShine/Code/Editor/Animation/UiAnimViewAnimNode.cpp @@ -110,10 +110,10 @@ CUiAnimViewAnimNode::CUiAnimViewAnimNode(IUiAnimSequence* pSequence, IUiAnimNode for (int i = 0; i < nodeCount; ++i) { IUiAnimNode* pNode = pSequence->GetNode(i); - IUiAnimNode* pParentNode = pNode->GetParent(); + IUiAnimNode* pNodeParentNode = pNode->GetParent(); // If our node is the parent, then the current node is a child of it - if (pAnimNode == pParentNode) + if (pAnimNode == pNodeParentNode) { CUiAnimViewAnimNodeFactory animNodeFactory; CUiAnimViewAnimNode* pNewUiAVAnimNode = animNodeFactory.BuildAnimNode(pSequence, pNode, this); @@ -510,20 +510,20 @@ bool CUiAnimViewAnimNode::BaseClassPropertyPotentiallyChanged( { for (const AZ::SerializeContext::ClassElement& baseElement : baseClassData->m_elements) { - size_t offset = baseClassOffset + baseElement.m_offset; + size_t baseOffset = baseClassOffset + baseElement.m_offset; if (baseElement.m_flags & AZ::SerializeContext::ClassElement::FLG_BASE_CLASS) { - if (BaseClassPropertyPotentiallyChanged(context, dstComponent, srcComponent, baseElement, offset)) + if (BaseClassPropertyPotentiallyChanged(context, dstComponent, srcComponent, baseElement, baseOffset)) { valueChanged = true; } } else { - if (HasComponentParamValueAzChanged(dstComponent, srcComponent, baseElement, offset)) + if (HasComponentParamValueAzChanged(dstComponent, srcComponent, baseElement, baseOffset)) { valueChanged = true; - AzEntityPropertyChanged(srcComponent, dstComponent, baseElement, offset); + AzEntityPropertyChanged(srcComponent, dstComponent, baseElement, baseOffset); } } } diff --git a/Gems/LyShine/Code/Editor/Animation/UiAnimViewTrack.cpp b/Gems/LyShine/Code/Editor/Animation/UiAnimViewTrack.cpp index 797154a50b..fc77a370d3 100644 --- a/Gems/LyShine/Code/Editor/Animation/UiAnimViewTrack.cpp +++ b/Gems/LyShine/Code/Editor/Animation/UiAnimViewTrack.cpp @@ -59,12 +59,12 @@ CUiAnimViewTrack::CUiAnimViewTrack(IUiAnimTrack* pTrack, CUiAnimViewAnimNode* pT { // Search for child tracks const unsigned int subTrackCount = m_pAnimTrack->GetSubTrackCount(); - for (unsigned int subTrackIndex = 0; subTrackIndex < subTrackCount; ++subTrackIndex) + for (unsigned int subTrackI = 0; subTrackI < subTrackCount; ++subTrackI) { - IUiAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackIndex); + IUiAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackI); CUiAnimViewTrackFactory trackFactory; - CUiAnimViewTrack* pNewUiAVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackIndex); + CUiAnimViewTrack* pNewUiAVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackI); m_childNodes.push_back(std::unique_ptr(pNewUiAVTrack)); } diff --git a/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp b/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp index 2eb840b253..5a080084e1 100644 --- a/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp +++ b/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp @@ -422,12 +422,12 @@ namespace Audio if (stereoToMono) { // Samples are interleaved now, copy only left channel to the output - float* inputData = reinterpret_cast(m_conversionBufferIn.m_data); - float* outputData = reinterpret_cast(m_conversionBufferOut.m_data); + float* bufferInputData = reinterpret_cast(m_conversionBufferIn.m_data); + float* bufferOutputData = reinterpret_cast(m_conversionBufferOut.m_data); for (AZ::u32 frame = 0; frame < numFrames; ++frame) { - outputData[frame] = *inputData++; - ++inputData; + bufferOutputData[frame] = *bufferInputData++; + ++bufferInputData; } } else // monoToStereo @@ -435,21 +435,21 @@ namespace Audio // Split single samples to both left and right channels if (shouldDeinterleave) { - float* inputData = reinterpret_cast(m_conversionBufferIn.m_data); - float** outputData = reinterpret_cast(m_conversionBufferOut.m_data); + float* bufferInputData = reinterpret_cast(m_conversionBufferIn.m_data); + float** bufferOutputData = reinterpret_cast(m_conversionBufferOut.m_data); for (AZ::u32 frame = 0; frame < numFrames; ++frame) { - outputData[0][frame] = outputData[1][frame] = inputData[frame]; + bufferOutputData[0][frame] = bufferOutputData[1][frame] = bufferInputData[frame]; } } else { - float* inputData = reinterpret_cast(m_conversionBufferIn.m_data); - float* outputData = reinterpret_cast(m_conversionBufferOut.m_data); + float* bufferInputData = reinterpret_cast(m_conversionBufferIn.m_data); + float* bufferOutputData = reinterpret_cast(m_conversionBufferOut.m_data); for (AZ::u32 frame = 0; frame < numFrames; ++frame) { - *outputData++ = inputData[frame]; - *outputData++ = inputData[frame]; + *bufferOutputData++ = bufferInputData[frame]; + *bufferOutputData++ = bufferInputData[frame]; } } } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index eaf89f3489..b0f1b221e8 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -263,9 +263,9 @@ namespace Multiplayer // Validate that we aren't already planning to remove this entity if (safeToExit) { - for (auto entityId : m_removeList) + for (auto remoteEntityId : m_removeList) { - if (entityId == entityId) + if (remoteEntityId == remoteEntityId) { safeToExit = false; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp index 8b00b5b71b..a5c0287cfd 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp @@ -340,31 +340,31 @@ namespace } // Pass in the associated class data so we can do more intensive lookups? - const AZ::SerializeContext::ClassData* classData = serializeContext.FindClassData(node.first); + const AZ::SerializeContext::ClassData* nodeClassData = serializeContext.FindClassData(node.first); - if (classData == nullptr) + if (nodeClassData == nullptr) { continue; } // Detect primitive types os we avoid making nodes out of them. // Or anything that is 'pure data' and should be populated through a different mechanism. - if (classData->m_azRtti && classData->m_azRtti->IsTypeOf()) + if (nodeClassData->m_azRtti && nodeClassData->m_azRtti->IsTypeOf()) { continue; } // Skip over some of our more dynamic nodes that we want to populate using different means - else if (classData->m_azRtti && classData->m_azRtti->IsTypeOf()) + else if (nodeClassData->m_azRtti && nodeClassData->m_azRtti->IsTypeOf()) { continue; } - else if (classData->m_azRtti && classData->m_azRtti->IsTypeOf()) + else if (nodeClassData->m_azRtti && nodeClassData->m_azRtti->IsTypeOf()) { continue; } else { - nodePaletteModel.RegisterCustomNode(categoryPath, node.first, node.second, classData); + nodePaletteModel.RegisterCustomNode(categoryPath, node.first, node.second, nodeClassData); } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp index 428f5eb290..3c21701fb0 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp @@ -563,13 +563,13 @@ namespace ScriptCanvasEditor else if (slotType == GraphCanvas::SlotTypes::DataSlot) { const AZ::EntityId& slotId2 = GetTargetId(); - const GraphCanvas::GraphId& graphId = GetGraphId(); + const GraphCanvas::GraphId& graphId2 = GetGraphId(); GraphCanvas::Endpoint endpoint; GraphCanvas::SlotRequestBus::EventResult(endpoint, slotId2, &GraphCanvas::SlotRequests::GetEndpoint); bool promotedElement = false; - GraphCanvas::GraphModelRequestBus::EventResult(promotedElement, graphId, &GraphCanvas::GraphModelRequests::PromoteToVariableAction, endpoint); + GraphCanvas::GraphModelRequestBus::EventResult(promotedElement, graphId2, &GraphCanvas::GraphModelRequests::PromoteToVariableAction, endpoint); if (promotedElement) { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index db45f6bfe3..2a485c9501 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -4090,23 +4090,23 @@ namespace ScriptCanvas auto userFunctionIter = m_userInsThatRequireTopology.find(nodeling); if (userFunctionIter != m_userInsThatRequireTopology.end()) { - auto& node = *userFunctionIter->first; - auto outSlots = node.GetSlotsByType(CombinedSlotType::ExecutionOut); + auto& userFunctionNode = *userFunctionIter->first; + auto outSlots = userFunctionNode.GetSlotsByType(CombinedSlotType::ExecutionOut); if (outSlots.empty() || !outSlots.front()) { - AddError(node.GetEntityId(), nullptr, ScriptCanvas::ParseErrors::NoOutSlotInFunctionDefinitionStart); + AddError(userFunctionNode.GetEntityId(), nullptr, ScriptCanvas::ParseErrors::NoOutSlotInFunctionDefinitionStart); return; } - if (!ExecutionContainsCyclesCheck(node, *outSlots.front())) + if (!ExecutionContainsCyclesCheck(userFunctionNode, *outSlots.front())) { auto definition = userFunctionIter->second; auto entrySlot = definition->GetId().m_slot; AZ_Assert(entrySlot, "Bad accounting in user function definition node"); AZStd::vector returnValues; UserOutCallCollector userOutCallCollector; - TraverseExecutionConnections(node, *entrySlot, userOutCallCollector); + TraverseExecutionConnections(userFunctionNode, *entrySlot, userOutCallCollector); const AZStd::unordered_set& uniqueNodelingsOut = userOutCallCollector.GetOutCalls(); for (const auto& returnCall : uniqueNodelingsOut) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Internal/Nodes/ExpressionNodeBase.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Internal/Nodes/ExpressionNodeBase.cpp index e7edcce002..8c0f5760a8 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Internal/Nodes/ExpressionNodeBase.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Internal/Nodes/ExpressionNodeBase.cpp @@ -121,13 +121,13 @@ namespace ScriptCanvas { if (slotId == ExpressionNodeBaseProperty::GetInSlotId(this)) { - for (const SlotId& slotId : m_dirtyInputs) + for (const SlotId& dirtySlotId : m_dirtyInputs) { - auto variableIter = m_slotToVariableMap.find(slotId); + auto variableIter = m_slotToVariableMap.find(dirtySlotId); if (variableIter != m_slotToVariableMap.end()) { - PushVariable(variableIter->second, (*FindDatum(slotId))); + PushVariable(variableIter->second, (*FindDatum(dirtySlotId))); } } diff --git a/Gems/WhiteBox/Code/Source/Core/WhiteBoxToolApi.cpp b/Gems/WhiteBox/Code/Source/Core/WhiteBoxToolApi.cpp index 5803f066ae..a6b9456f98 100644 --- a/Gems/WhiteBox/Code/Source/Core/WhiteBoxToolApi.cpp +++ b/Gems/WhiteBox/Code/Source/Core/WhiteBoxToolApi.cpp @@ -2060,23 +2060,23 @@ namespace WhiteBox polygonHandle.m_faceHandles.push_back(faceHandleToVisit); // for all halfedges - for (const auto halfedgeHandle : faceHalfedges) + for (const auto faceHalfedgeHandle : faceHalfedges) { - const EdgeHandle edgeHandle = HalfedgeEdgeHandle(whiteBox, halfedgeHandle); + const EdgeHandle edgeHandle = HalfedgeEdgeHandle(whiteBox, faceHalfedgeHandle); // if we haven't seen this halfedge before and we want to track it, // store it in visited halfedges - if (halfedgeHandle != oppositeHalfedgeHandle + if (faceHalfedgeHandle != oppositeHalfedgeHandle // ignore border halfedges (not inside the polygon) - && AZStd::find(borderHalfedgeHandles.cbegin(), borderHalfedgeHandles.cend(), halfedgeHandle) == + && AZStd::find(borderHalfedgeHandles.cbegin(), borderHalfedgeHandles.cend(), faceHalfedgeHandle) == borderHalfedgeHandles.cend() // ensure we do not visit the same halfedge again - && AZStd::find(visitedHalfedges.cbegin(), visitedHalfedges.cend(), halfedgeHandle) == + && AZStd::find(visitedHalfedges.cbegin(), visitedHalfedges.cend(), faceHalfedgeHandle) == visitedHalfedges.cend() // ignore the halfedge if we've already tracked it in our 'building' list && AZStd::find(buildingEdgeHandles.cbegin(), buildingEdgeHandles.cend(), edgeHandle) == buildingEdgeHandles.cend()) { - halfedgesToVisit.push_back(HalfedgeOppositeHalfedgeHandle(whiteBox, halfedgeHandle)); + halfedgesToVisit.push_back(HalfedgeOppositeHalfedgeHandle(whiteBox, faceHalfedgeHandle)); } } } @@ -3198,10 +3198,10 @@ namespace WhiteBox // - add bottom faces if mesh was 2d previously (reverse winding order) FaceHandles allFacesToRemove = polygonHandle.m_faceHandles; - for (const auto& polygonHandle : polygonHandlesToRemove) + for (const auto& polygonHandleToRemove : polygonHandlesToRemove) { allFacesToRemove.insert( - allFacesToRemove.end(), polygonHandle.m_faceHandles.cbegin(), polygonHandle.m_faceHandles.cend()); + allFacesToRemove.end(), polygonHandleToRemove.m_faceHandles.cbegin(), polygonHandleToRemove.m_faceHandles.cend()); } // remove all faces that were already there diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index f53b8aa769..357d578c44 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -73,7 +73,6 @@ ly_append_configurations_options( /wd4389 # comparison, signed/unsigned mismatch /wd4436 # the result of unary operator may be unaligned /wd4450 # declaration hides global declaration - /wd4457 # declaration hides function parameter # Enabling warnings that are disabled by default from /W4 # https://docs.microsoft.com/en-us/cpp/preprocessor/compiler-warnings-that-are-off-by-default?view=vs-2019 From 1f48985a0e325164af62561f6983ebac4a620e0c Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Fri, 4 Jun 2021 18:09:26 +0000 Subject: [PATCH 45/45] Update Blast to the latest version, eb169fe (#1076) --- cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index fa1326b63d..1a2cfa4049 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -30,11 +30,11 @@ ly_associate_package(PACKAGE_NAME azslc-1.7.21-rev1-multiplatform ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) -ly_associate_package(PACKAGE_NAME Blast-1.1.7-rev1-multiplatform TARGETS Blast PACKAGE_HASH 36b8f393bcd25d0f85cfc7a831ebbdac881e6054c4f0735649966aa6aa86e6f0) ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform TARGETS PVRTexTool PACKAGE_HASH d0d6da61c7557de0d2c71fc35ba56c3be49555b703f0e853d4c58225537acf1e) # platform-specific: ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-windows TARGETS AWSGameLiftServerSDK PACKAGE_HASH a0586b006e4def65cc25f388de17dc475e417dc1e6f9d96749777c88aa8271b0) +ly_associate_package(PACKAGE_NAME Blast-v1.1.7_rc2-9-geb169fe-rev1-windows TARGETS Blast PACKAGE_HASH 216df71f4ffaf4a6ea3f2e77e5f27d68f2325e717fbd1626b00c785b82cd1b67) ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev2-windows TARGETS DirectXShaderCompilerDxc PACKAGE_HASH decc53e97c7ddda9c7f853a30af7808a7b652a912f59ad2cd4bca5d308aae2c4) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-windows TARGETS SPIRVCross PACKAGE_HASH 7d601ea9d625b1d509d38bd132a1f433d7e895b16adab76bac6103567a7a6817) ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-windows TARGETS freetype PACKAGE_HASH 88dedc86ccb8c92f14c2c033e51ee7d828fa08eafd6475c6aa963938a99f4bf3)