From 6643b4b53cb209e57904c5ff6b51e08d481c98eb Mon Sep 17 00:00:00 2001 From: "T.J. McGrath-Daly" Date: Mon, 6 Dec 2021 08:48:24 +0800 Subject: [PATCH 01/20] Fix: LOD stops animation Signed-off-by: T.J. McGrath-Daly --- .../SkinnedMeshFeatureProcessor.cpp | 65 ++++++++++++------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp index 37b18291dc..8cd20b77d5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp @@ -204,35 +204,56 @@ namespace AZ // do the enumeration for each view, keep track of the lowest lod for each entry, // and submit the appropriate dispatch item - //the [1][1] element of a perspective projection matrix stores cot(FovY/2) (equal to 2*nearPlaneDistance/nearPlaneHeight), - //which is used to determine the (vertical) projected size in screen space - const float yScale = viewToClip.GetElement(1, 1); - const bool isPerspective = viewToClip.GetElement(3, 3) == 0.f; - const Vector3 cameraPos = view->GetViewToWorldMatrix().GetTranslation(); - - const Vector3 pos = cullable.m_cullData.m_boundingSphere.GetCenter(); - - const float approxScreenPercentage = RPI::ModelLodUtils::ApproxScreenPercentage( - pos, cullable.m_lodData.m_lodSelectionRadius, cameraPos, yScale, isPerspective); - - for (size_t lodIndex = 0; lodIndex < cullable.m_lodData.m_lods.size(); ++lodIndex) + switch (cullable.m_lodData.m_lodConfiguration.m_lodType) { - const RPI::Cullable::LodData::Lod& lod = cullable.m_lodData.m_lods[lodIndex]; - - //Note that this supports overlapping lod ranges (to support cross-fading lods, for example) - if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax) + case RPI::Cullable::LodType::SpecificLod: + { + AZStd::lock_guard lock(m_dispatchItemMutex); + auto lodIndex = cullable.m_lodData.m_lodConfiguration.m_lodOverride; + m_skinningDispatches.insert(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem()); + for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy.m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++) { - AZStd::lock_guard lock(m_dispatchItemMutex); - m_skinningDispatches.insert(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem()); - for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy.m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++) + const MorphTargetDispatchItem* dispatchItem = renderProxy.m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get(); + if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon) { - const MorphTargetDispatchItem* dispatchItem = renderProxy.m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get(); - if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon) + m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem()); + } + } + } + break; + case RPI::Cullable::LodType::ScreenCoverage: + default: + //the [1][1] element of a perspective projection matrix stores cot(FovY/2) (equal to 2*nearPlaneDistance/nearPlaneHeight), + //which is used to determine the (vertical) projected size in screen space + const float yScale = viewToClip.GetElement(1, 1); + const bool isPerspective = viewToClip.GetElement(3, 3) == 0.f; + const Vector3 cameraPos = view->GetViewToWorldMatrix().GetTranslation(); + + const Vector3 pos = cullable.m_cullData.m_boundingSphere.GetCenter(); + + const float approxScreenPercentage = RPI::ModelLodUtils::ApproxScreenPercentage( + pos, cullable.m_lodData.m_lodSelectionRadius, cameraPos, yScale, isPerspective); + + for (size_t lodIndex = 0; lodIndex < cullable.m_lodData.m_lods.size(); ++lodIndex) + { + const RPI::Cullable::LodData::Lod& lod = cullable.m_lodData.m_lods[lodIndex]; + + //Note that this supports overlapping lod ranges (to support cross-fading lods, for example) + if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax) + { + AZStd::lock_guard lock(m_dispatchItemMutex); + m_skinningDispatches.insert(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem()); + for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy.m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++) { - m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem()); + const MorphTargetDispatchItem* dispatchItem = renderProxy.m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get(); + if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon) + { + m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem()); + } } } } + break; } } } From 7af3bef84c7170b0d91f812a30a476ffb37a4107 Mon Sep 17 00:00:00 2001 From: "T.J. McGrath-Daly" Date: Fri, 15 Oct 2021 15:15:26 +0800 Subject: [PATCH 02/20] Model drag causes crash Signed-off-by: T.J. McGrath-Daly --- Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp index 861271fdb3..0c05da6981 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp @@ -434,6 +434,17 @@ namespace EMotionFX m_morphSetups.resize(numLODs); AZStd::fill(begin(m_morphSetups), AZStd::next(begin(m_morphSetups), numLODs), nullptr); } + else + { + if (m_morphSetups.size() < numLODs) + { + AZ::u32 num = m_morphSetups.empty() ? 0 : (AZ::u32)m_morphSetups.size(); + for (AZ::u32 i = num; i < numLODs; ++i) + { + m_morphSetups.push_back(nullptr); + } + } + } } // removes all node meshes and stacks From 02acf2f65ea3ecb606a6f9411efc257fd3e51f3c Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Sat, 18 Sep 2021 23:57:52 -0700 Subject: [PATCH 03/20] Updated MaterialPropertyId class in preparation for nested material property sets. Here the class has been generalized for a list of group names and a final property name, rather than assuming a single group containing the property. This included removing the unused GetPropertyName and GetGroupName functions. All that's really need from this class is conversion to a full property ID string. Testing: New unit test. Reprocessed all core material types and StandardPBR test materials used in Atom Sample Viewer's material screenshot test. Atom Sample Viewer material screenshot test script. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../RPI.Edit/Material/MaterialPropertyId.h | 18 +-- .../RPI.Edit/Material/MaterialPropertyId.cpp | 83 ++++++----- .../Material/MaterialTypeSourceData.cpp | 12 +- .../Material/MaterialPropertyIdTests.cpp | 131 ++++++++++++++++++ Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake | 1 + .../Code/Source/Document/MaterialDocument.cpp | 8 +- .../MaterialInspector/MaterialInspector.cpp | 4 +- .../EditorMaterialComponentInspector.cpp | 2 +- .../Material/EditorMaterialComponentUtil.cpp | 4 +- .../EditorMaterialModelUvNameMapInspector.cpp | 4 +- 10 files changed, 210 insertions(+), 57 deletions(-) create mode 100644 Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h index 77d49f3407..4b6d78c092 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h @@ -9,6 +9,7 @@ #pragma once #include +#include namespace AZ { @@ -16,27 +17,28 @@ namespace AZ { class MaterialAsset; - //! Utility for building material property names consisting of a group name and a property sub-name. - //! Represented as "[groupName].[propertyName]". - //! The group name is optional, in which case the ID will just be "[propertyName]". + //! Utility for building material property IDs. + //! These IDs are represented like "groupA.groupB.[...].propertyName". + //! The groups are optional, in which case the full property ID will just be like "propertyName". class MaterialPropertyId { public: static bool IsValidName(AZStd::string_view name); static bool IsValidName(const AZ::Name& name); - //! Creates a MaterialPropertyId from a full name string like "[groupName].[propertyName]" or just "[propertyName]" + //! Creates a MaterialPropertyId from a full name string like "groupA.groupB.[...].propertyName" or just "propertyName". + //! Also checks the name for validity. static MaterialPropertyId Parse(AZStd::string_view fullPropertyId); MaterialPropertyId() = default; + explicit MaterialPropertyId(AZStd::string_view propertyName); MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName); MaterialPropertyId(const Name& groupName, const Name& propertyName); + MaterialPropertyId(const AZStd::array_view names); AZ_DEFAULT_COPY_MOVE(MaterialPropertyId); - const Name& GetGroupName() const; - const Name& GetPropertyName() const; - const Name& GetFullName() const; + operator const Name&() const; //! Returns a pointer to the full name ("[groupName].[propertyName]"). //! This is included for convenience so it can be used for error messages in the same way an AZ::Name is used. @@ -52,8 +54,6 @@ namespace AZ private: Name m_fullName; - Name m_groupName; - Name m_propertyName; }; } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index e74ec3e6e0..1be5c4485c 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -27,63 +27,84 @@ namespace AZ bool MaterialPropertyId::IsValid() const { - const bool groupNameIsValid = m_groupName.IsEmpty() || IsValidName(m_groupName); - const bool propertyNameIsValid = IsValidName(m_propertyName); - return groupNameIsValid && propertyNameIsValid; + return !m_fullName.IsEmpty(); } MaterialPropertyId MaterialPropertyId::Parse(AZStd::string_view fullPropertyId) { AZStd::vector tokens; - AzFramework::StringFunc::Tokenize(fullPropertyId.data(), tokens, '.', true, true); + AzFramework::StringFunc::Tokenize(fullPropertyId, tokens, '.', true, true); - if (tokens.size() == 1) + if (tokens.empty()) { - return MaterialPropertyId{"", tokens[0]}; + AZ_Error("MaterialPropertyId", false, "Property ID is empty.", fullPropertyId.data()); + return MaterialPropertyId{}; } - else if (tokens.size() == 2) + + for (const auto& token : tokens) { - return MaterialPropertyId{tokens[0], tokens[1]}; + if (!IsValidName(token)) + { + AZ_Error("MaterialPropertyId", false, "Property ID '%.*s' is not a valid identifier.", AZ_STRING_ARG(fullPropertyId)); + return MaterialPropertyId{}; + } + } + + MaterialPropertyId id; + id.m_fullName = fullPropertyId; + return id; + } + + MaterialPropertyId::MaterialPropertyId(AZStd::string_view propertyName) + { + if (!IsValidName(propertyName)) + { + AZ_Error("MaterialPropertyId", false, "Property name '%.*s' is not a valid identifier.", AZ_STRING_ARG(propertyName)); } else { - AZ_Error("MaterialPropertyId", false, "Property ID '%s' is not a valid identifier.", fullPropertyId.data()); - return MaterialPropertyId{}; + m_fullName = propertyName; } } MaterialPropertyId::MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName) - : MaterialPropertyId(Name{groupName}, Name{propertyName}) { - } - - MaterialPropertyId::MaterialPropertyId(const Name& groupName, const Name& propertyName) - { - AZ_Error("MaterialPropertyId", groupName.IsEmpty() || IsValidName(groupName), "Group name '%s' is not a valid identifier.", groupName.GetCStr()); - AZ_Error("MaterialPropertyId", IsValidName(propertyName), "Property name '%s' is not a valid identifier.", propertyName.GetCStr()); - m_groupName = groupName; - m_propertyName = propertyName; - if (groupName.IsEmpty()) + if (!IsValidName(groupName)) { - m_fullName = m_propertyName.GetStringView(); + AZ_Error("MaterialPropertyId", false, "Group name '%.*s' is not a valid identifier.", AZ_STRING_ARG(groupName)); + } + else if (!IsValidName(propertyName)) + { + AZ_Error("MaterialPropertyId", false, "Property name '%.*s' is not a valid identifier.", AZ_STRING_ARG(propertyName)); } else { - m_fullName = AZStd::string::format("%s.%s", m_groupName.GetCStr(), m_propertyName.GetCStr()); + m_fullName = AZStd::string::format("%.*s.%.*s", AZ_STRING_ARG(groupName), AZ_STRING_ARG(propertyName)); } } - - const Name& MaterialPropertyId::GetGroupName() const + + MaterialPropertyId::MaterialPropertyId(const Name& groupName, const Name& propertyName) + : MaterialPropertyId(groupName.GetStringView(), propertyName.GetStringView()) { - return m_groupName; + } + + MaterialPropertyId::MaterialPropertyId(const AZStd::array_view names) + { + for (const auto& name : names) + { + if (!IsValidName(name)) + { + AZ_Error("MaterialPropertyId", false, "'%s' is not a valid identifier.", name.c_str()); + return; + } + } + + AZStd::string fullName; + AzFramework::StringFunc::Join(fullName, names.begin(), names.end(), "."); + m_fullName = fullName; } - const Name& MaterialPropertyId::GetPropertyName() const - { - return m_propertyName; - } - - const Name& MaterialPropertyId::GetFullName() const + MaterialPropertyId::operator const Name&() const { return m_fullName; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 87c064f571..ddc2bc842b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -400,7 +400,7 @@ namespace AZ continue; } - materialTypeAssetCreator.BeginMaterialProperty(propertyId.GetFullName(), property.m_dataType); + materialTypeAssetCreator.BeginMaterialProperty(propertyId, property.m_dataType); if (property.m_dataType == MaterialPropertyDataType::Enum) { @@ -454,18 +454,18 @@ namespace AZ if (result == MaterialUtils::GetImageAssetResult::Missing) { materialTypeAssetCreator.ReportError( - "Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), + "Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), property.m_value.GetValue().data()); } else { - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); + materialTypeAssetCreator.SetPropertyValue(propertyId, imageAsset); } } break; case MaterialPropertyDataType::Enum: { - MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); + MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAssetCreator.GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); AZ::Name enumName = AZ::Name(property.m_value.GetValue()); @@ -476,12 +476,12 @@ namespace AZ } else { - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue); + materialTypeAssetCreator.SetPropertyValue(propertyId, enumValue); } } break; default: - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.m_value); + materialTypeAssetCreator.SetPropertyValue(propertyId, property.m_value); break; } } diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp new file mode 100644 index 0000000000..2b729ed8ef --- /dev/null +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace UnitTest +{ + using namespace AZ; + using namespace RPI; + + class MaterialPropertyIdTests + : public RPITestFixture + { + }; + + TEST_F(MaterialPropertyIdTests, TestConstructWithPropertyName) + { + MaterialPropertyId id{"color"}; + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "color"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"color"}); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithPropertyName_BadName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id{"color?"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames) + { + MaterialPropertyId id{"baseColor", "factor"}; + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "baseColor.factor"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"baseColor.factor"}); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames_BadGroupName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id{"layer1.baseColor", "factor"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames_BadPropertyName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id{"baseColor", ".factor"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleNames) + { + AZStd::vector names{"layer1", "clearCoat", "normal", "factor"}; + MaterialPropertyId id{names}; + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "layer1.clearCoat.normal.factor"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"layer1.clearCoat.normal.factor"}); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleNames_BadName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + AZStd::vector names{"layer1", "clear-coat", "normal", "factor"}; + MaterialPropertyId id{names}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestParse) + { + MaterialPropertyId id = MaterialPropertyId::Parse("layer1.clearCoat.normal.factor"); + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "layer1.clearCoat.normal.factor"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"layer1.clearCoat.normal.factor"}); + } + + TEST_F(MaterialPropertyIdTests, TestParse_BadName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id = MaterialPropertyId::Parse("layer1.clearCoat.normal,factor"); + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestNameValidity) + { + EXPECT_TRUE(MaterialPropertyId::IsValidName("a")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("z")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("A")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("Z")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("_")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("m_layer10bazBAZ")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("1layer")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("base-color")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("base.color")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("base/color")); + } +} diff --git a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake index 5d67948ac8..57ee71e412 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake @@ -37,6 +37,7 @@ set(FILES Tests/Material/MaterialSourceDataTests.cpp Tests/Material/MaterialFunctorTests.cpp Tests/Material/MaterialFunctorSourceDataSerializerTests.cpp + Tests/Material/MaterialPropertyIdTests.cpp Tests/Material/MaterialPropertyValueSourceDataTests.cpp Tests/Material/MaterialTests.cpp Tests/Model/ModelTests.cpp diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 641d586ea7..8f25e41827 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -589,7 +589,7 @@ namespace MaterialEditor const MaterialPropertyId propertyId(groupName, propertyName); - const auto it = m_properties.find(propertyId.GetFullName()); + const auto it = m_properties.find(propertyId); if (it != m_properties.end() && propertyFilter(it->second)) { MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); @@ -597,7 +597,7 @@ namespace MaterialEditor { if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyId.GetFullName(), propertyDefinition, propertyValue)) { - AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str()); + AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetCStr(), m_absolutePath.c_str()); result = false; return false; } @@ -783,7 +783,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicPropertyConfig propertyConfig; // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = MaterialPropertyId(groupName, propertyName).GetCStr(); + propertyConfig.m_id = MaterialPropertyId(groupName, propertyName); const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); const bool propertyIndexInBounds = propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size(); @@ -854,7 +854,7 @@ namespace MaterialEditor propertyConfig = {}; propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::String; - propertyConfig.m_id = MaterialPropertyId(UvGroupName, shaderInput).GetCStr(); + propertyConfig.m_id = MaterialPropertyId(UvGroupName, shaderInput); propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = shaderInput; propertyConfig.m_groupName = "UV Sets"; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp index 7790b9bef5..0af051894d 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp @@ -152,7 +152,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupName, uvNamePair.m_shaderInput.ToString()).GetFullName()); + AZ::RPI::MaterialPropertyId(groupName, uvNamePair.m_shaderInput.ToString())); group.m_properties.push_back(property); property.SetValue(property.GetConfig().m_parentValue); @@ -189,7 +189,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name).GetFullName()); + AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name)); group.m_properties.push_back(property); } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index bfa9f1d36f..b20fe5802d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -310,7 +310,7 @@ namespace AZ AtomToolsFramework::DynamicPropertyConfig propertyConfig; // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name).GetFullName(); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name); AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, propertyDefinition); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index d3e125426c..f46876fdfb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -116,7 +116,7 @@ namespace AZ editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition){ const AZ::RPI::MaterialPropertyId propertyId(groupName, propertyName); const AZ::RPI::MaterialPropertyIndex propertyIndex = - editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); + editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; @@ -128,7 +128,7 @@ namespace AZ } // Check for and apply any property overrides before saving property values - auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId.GetFullName()); + auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId); if (propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) { propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp index 0cf6410fc5..53d7980fdc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp @@ -96,7 +96,7 @@ namespace AZ const AZStd::string materialUvName = m_materialUvNames[i].m_uvName.GetStringView(); propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Enum; - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput).GetFullName(); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput); propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = materialUvName; propertyConfig.m_description = shaderInput; @@ -248,7 +248,7 @@ namespace AZ const AZStd::string materialUvName = m_materialUvNames[i].m_uvName.GetStringView(); propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Enum; - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput).GetFullName(); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput); propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = materialUvName; propertyConfig.m_description = shaderInput; From 8d5a53ab9313069b758ea904fe572911e331b218 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 12 Jan 2022 15:31:37 -0800 Subject: [PATCH 04/20] Minor changes per code review feedback. Added explicit keyword. Renmoved unnecessary local variable. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h | 2 +- .../RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h index 4b6d78c092..5b3c0488cb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h @@ -34,7 +34,7 @@ namespace AZ explicit MaterialPropertyId(AZStd::string_view propertyName); MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName); MaterialPropertyId(const Name& groupName, const Name& propertyName); - MaterialPropertyId(const AZStd::array_view names); + explicit MaterialPropertyId(const AZStd::array_view names); AZ_DEFAULT_COPY_MOVE(MaterialPropertyId); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index 1be5c4485c..a1fee51d0a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -99,9 +99,7 @@ namespace AZ } } - AZStd::string fullName; - AzFramework::StringFunc::Join(fullName, names.begin(), names.end(), "."); - m_fullName = fullName; + AzFramework::StringFunc::Join(m_fullName, names.begin(), names.end(), "."); } MaterialPropertyId::operator const Name&() const From 534843df0f478a122cc082ba9814f3967e5b5c75 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 12 Jan 2022 15:32:49 -0800 Subject: [PATCH 05/20] Added MaterialPropertyId::GetStringView() utility function. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Include/Atom/RPI.Edit/Material/MaterialPropertyId.h | 6 ++++++ .../Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h index 5b3c0488cb..fd63494f30 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h @@ -41,8 +41,14 @@ namespace AZ operator const Name&() const; //! Returns a pointer to the full name ("[groupName].[propertyName]"). + //! Same as Name::GetCStr() //! This is included for convenience so it can be used for error messages in the same way an AZ::Name is used. const char* GetCStr() const; + + //! Returns a string_view of the full name ("[groupName].[propertyName]"). + //! Same as Name::GetStringView() + //! This is included for convenience so it can be used for string comparison in the same way an AZ::Name is used. + AZStd::string_view GetStringView() const; //! Returns a hash of the full name. This is needed for compatibility with NameIdReflectionMap. Name::Hash GetHash() const; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index a1fee51d0a..4880de33fe 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -111,6 +111,11 @@ namespace AZ { return m_fullName.GetCStr(); } + + AZStd::string_view MaterialPropertyId::GetStringView() const + { + return m_fullName.GetStringView(); + } Name::Hash MaterialPropertyId::GetHash() const { From b9ba9f5ca83f31687f6b3c94e092e8c49759fb8d Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 20 Jan 2022 16:11:31 -0800 Subject: [PATCH 06/20] Got RPI unit tests building and passing again. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../RPI.Edit/Material/MaterialPropertyId.cpp | 4 +++- .../RPI.Edit/Material/MaterialSourceData.cpp | 6 +++--- .../Material/MaterialTypeSourceData.cpp | 17 +++++++++++------ .../Tests/Material/MaterialSourceDataTests.cpp | 2 +- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index 4880de33fe..d123fe33b7 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -99,7 +99,9 @@ namespace AZ } } - AzFramework::StringFunc::Join(m_fullName, names.begin(), names.end(), "."); + AZStd::string fullName; // m_fullName is a Name, not a string, so we have to join into a local variable temporarily. + AzFramework::StringFunc::Join(fullName, names.begin(), names.end(), "."); + m_fullName = fullName; } MaterialPropertyId::operator const Name&() const diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index b921b186c0..2fa4ff648e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -340,16 +340,16 @@ namespace AZ if (result == MaterialUtils::GetImageAssetResult::Missing) { materialAssetCreator.ReportWarning( - "Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), + "Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), property.second.m_value.GetValue().data()); } imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); + materialAssetCreator.SetPropertyValue(propertyId, imageAsset); } else { - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value); + materialAssetCreator.SetPropertyValue(propertyId, property.second.m_value); } } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index ddc2bc842b..3a5992f8dd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -140,7 +140,7 @@ namespace AZ { if (action.m_operation == "rename") { - if (action.m_renameFrom == propertyId.GetFullName().GetStringView()) + if (action.m_renameFrom == propertyId.GetStringView()) { propertyId = MaterialPropertyId::Parse(action.m_renameTo); renamed = true; @@ -177,14 +177,19 @@ namespace AZ // Do the search again with the new names - groupIter = m_propertyLayout.m_properties.find(propertyId.GetGroupName().GetStringView()); - if (groupIter != m_propertyLayout.m_properties.end()) + AZStd::vector tokens; + AZ::StringFunc::Tokenize(propertyId.GetStringView(), tokens, ".", true, true); + if (tokens.size() == 2) { - for (const PropertyDefinition& property : groupIter->second) + groupIter = m_propertyLayout.m_properties.find(tokens[0]); + if (groupIter != m_propertyLayout.m_properties.end()) { - if (property.m_name == propertyId.GetPropertyName().GetStringView()) + for (const PropertyDefinition& property : groupIter->second) { - return &property; + if (property.m_name == tokens[1]) + { + return &property; + } } } } diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp index 5e09fe6612..94518c6aef 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp @@ -905,7 +905,7 @@ namespace UnitTest JsonTestResult loadResult = LoadTestDataFromJson(material, inputJson); auto materialAssetResult = material.CreateMaterialAsset(Uuid::CreateRandom(), "test.material", AZ::RPI::MaterialAssetProcessingMode::PreBake); EXPECT_TRUE(materialAssetResult); - MaterialPropertyIndex propertyIndex = materialAssetResult.GetValue()->GetMaterialPropertiesLayout()->FindPropertyIndex(MaterialPropertyId{groupName, propertyName}.GetFullName()); + MaterialPropertyIndex propertyIndex = materialAssetResult.GetValue()->GetMaterialPropertiesLayout()->FindPropertyIndex(MaterialPropertyId{groupName, propertyName}); CheckSimilar(expectedFinalValue, materialAssetResult.GetValue()->GetPropertyValues()[propertyIndex.GetIndex()].GetValue()); } From 42b7f21689e99298df71c1591162509be73994ca Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 21 Jan 2022 11:55:02 -0800 Subject: [PATCH 07/20] Fixed a place where GetFullName was still being used. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Source/Material/EditorMaterialComponentUtil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index f46876fdfb..d4dd4f3a0e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -134,7 +134,7 @@ namespace AZ propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); } - if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId.GetFullName(), propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId, propertyDefinition, propertyValue)) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); result = false; From 3e5c1cee1eca80e6678e4e097bd22cf9ca28d035 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 21 Jan 2022 11:56:32 -0800 Subject: [PATCH 08/20] Fixed a place where GetFullName was still being used. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../MaterialEditor/Code/Source/Document/MaterialDocument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 8f25e41827..2a0d91d0ad 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -595,7 +595,7 @@ namespace MaterialEditor MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); if (propertyValue.IsValid()) { - if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyId.GetFullName(), propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyId, propertyDefinition, propertyValue)) { AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetCStr(), m_absolutePath.c_str()); result = false; From f20bf38f8886f9128e44c23f55f06ed70c501b04 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 23 Jan 2022 11:16:56 -0600 Subject: [PATCH 09/20] Atom Tools: Changed ME preset browser dialog into generic asset grid dialog in ATF Moving more potentially shared code out of the material editor into atom tools framework. This change consolidates the lighting preset browser, model preset browser, and the base dialogue that they shared into a single, grid based, asset selection dialog. AssetGridDialog should appear as a move and rename of PresetBrowserDialog but there are probably too many differences with new variable renames and SelectableAsset struct. Along the way I found examples showing that event bus broadcast accepted generic functions and lambdas. Used this to do a minor cleanup of the viewport settings inspector where the preset dialogs were initialized and other places that did several back to back bus calls. Signed-off-by: Guthrie Adams --- .../AssetGridDialog/AssetGridDialog.h | 69 +++++++ .../AssetGridDialog/AssetGridDialog.cpp | 179 ++++++++++++++++++ .../AssetGridDialog/AssetGridDialog.ui} | 6 +- .../Code/atomtoolsframework_files.cmake | 3 + .../LightingPresetBrowserDialog.cpp | 73 ------- .../LightingPresetBrowserDialog.h | 36 ---- .../ModelPresetBrowserDialog.cpp | 69 ------- .../ModelPresetBrowserDialog.h | 36 ---- .../PresetBrowserDialog.cpp | 133 ------------- .../PresetBrowserDialog.h | 46 ----- .../ViewportSettingsInspector.cpp | 146 ++++++++++---- .../Code/materialeditor_files.cmake | 7 - 12 files changed, 365 insertions(+), 438 deletions(-) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.cpp rename Gems/Atom/Tools/{MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui => AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.ui} (86%) delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h new file mode 100644 index 0000000000..afbe99a843 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#endif + +#include +#include + +class QListWidgetItem; + +namespace Ui +{ + class AssetGridDialog; +} + +namespace AtomToolsFramework +{ + //! Widget for managing and selecting from a library of assets + class AssetGridDialog : public QDialog + { + Q_OBJECT + public: + struct SelectableAsset + { + AZ::Data::AssetId m_assetId; + QString m_title; + }; + + using SelectableAssetVector = AZStd::vector; + + AssetGridDialog( + const QString& title, + const SelectableAssetVector& selectableAssets, + const AZ::Data::AssetId& selectedAsset, + const QSize& tileSize, + QWidget* parent = nullptr); + + ~AssetGridDialog(); + + Q_SIGNALS: + void AssetSelected(const AZ::Data::AssetId& assetId); + + private: + AZ_DISABLE_COPY_MOVE(AssetGridDialog); + + QListWidgetItem* CreateListItem(const SelectableAsset& selectableAsset); + void SetupAssetList(); + void SetupSearchWidget(); + void SetupDialogButtons(); + void ApplySearchFilter(); + void ShowSearchMenu(const QPoint& pos); + void SelectCurrentAsset(); + void SelectInitialAsset(); + + QSize m_tileSize; + AZ::Data::AssetId m_initialSelectedAsset; + QScopedPointer m_ui; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.cpp new file mode 100644 index 0000000000..ed19c4890d --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace AtomToolsFramework +{ + AssetGridDialog::AssetGridDialog( + const QString& title, + const SelectableAssetVector& selectableAssets, + const AZ::Data::AssetId& selectedAsset, + const QSize& tileSize, + QWidget* parent) + : QDialog(parent) + , m_tileSize(tileSize) + , m_initialSelectedAsset(selectedAsset) + , m_ui(new Ui::AssetGridDialog) + { + m_ui->setupUi(this); + + QSignalBlocker signalBlocker(this); + + setWindowTitle(title); + + SetupAssetList(); + SetupSearchWidget(); + SetupDialogButtons(); + setModal(true); + + QListWidgetItem* selectedItem = nullptr; + for (const auto& selectableAsset : selectableAssets) + { + QListWidgetItem* item = CreateListItem(selectableAsset); + if (!selectedItem || m_initialSelectedAsset == selectableAsset.m_assetId) + { + selectedItem = item; + } + } + + m_ui->m_assetList->sortItems(); + + if (selectedItem) + { + m_ui->m_assetList->setCurrentItem(selectedItem); + m_ui->m_assetList->scrollToItem(selectedItem); + } + } + + AssetGridDialog::~AssetGridDialog() + { + } + + QListWidgetItem* AssetGridDialog::CreateListItem(const SelectableAsset& selectableAsset) + { + const int itemBorder = aznumeric_cast( + AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/ItemBorder", 4)); + const int itemSpacing = aznumeric_cast( + AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/ItemSpacing", 10)); + const int headerHeight = aznumeric_cast( + AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/HeaderHeight", 15)); + + const QSize gridSize = m_ui->m_assetList->gridSize(); + m_ui->m_assetList->setGridSize(QSize( + AZStd::max(gridSize.width(), m_tileSize.width() + itemSpacing), + AZStd::max(gridSize.height(), m_tileSize.height() + itemSpacing + headerHeight))); + + QListWidgetItem* item = new QListWidgetItem(m_ui->m_assetList); + item->setData(Qt::DisplayRole, selectableAsset.m_title); + item->setData(Qt::UserRole, QString(selectableAsset.m_assetId.ToString().c_str())); + item->setSizeHint(m_tileSize + QSize(itemBorder, itemBorder + headerHeight)); + m_ui->m_assetList->addItem(item); + + QWidget* itemWidget = new QWidget(m_ui->m_assetList); + itemWidget->setLayout(new QVBoxLayout(itemWidget)); + itemWidget->layout()->setSpacing(0); + itemWidget->layout()->setMargin(0); + + AzQtComponents::ElidingLabel* header = new AzQtComponents::ElidingLabel(itemWidget); + header->setText(selectableAsset.m_title); + header->setFixedSize(QSize(m_tileSize.width(), headerHeight)); + header->setMargin(0); + header->setStyleSheet("background-color: rgb(35, 35, 35)"); + AzQtComponents::Text::addPrimaryStyle(header); + AzQtComponents::Text::addLabelStyle(header); + itemWidget->layout()->addWidget(header); + + AzToolsFramework::Thumbnailer::ThumbnailWidget* thumbnail = new AzToolsFramework::Thumbnailer::ThumbnailWidget(itemWidget); + thumbnail->setFixedSize(m_tileSize); + thumbnail->SetThumbnailKey( + MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, selectableAsset.m_assetId), + AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext); + thumbnail->updateGeometry(); + itemWidget->layout()->addWidget(thumbnail); + + m_ui->m_assetList->setItemWidget(item, itemWidget); + + return item; + } + + void AssetGridDialog::SetupAssetList() + { + m_ui->m_assetList->setFlow(QListView::LeftToRight); + m_ui->m_assetList->setResizeMode(QListView::Adjust); + m_ui->m_assetList->setGridSize(QSize(0, 0)); + m_ui->m_assetList->setWrapping(true); + + QObject::connect(m_ui->m_assetList, &QListWidget::currentItemChanged, [this](){ SelectCurrentAsset(); }); + } + + void AssetGridDialog::SetupSearchWidget() + { + m_ui->m_searchWidget->setReadOnly(false); + m_ui->m_searchWidget->setContextMenuPolicy(Qt::CustomContextMenu); + AzQtComponents::LineEdit::applySearchStyle(m_ui->m_searchWidget); + connect(m_ui->m_searchWidget, &QLineEdit::textChanged, this, [this](){ ApplySearchFilter(); }); + connect(m_ui->m_searchWidget, &QWidget::customContextMenuRequested, this, [this](const QPoint& pos){ ShowSearchMenu(pos); }); + } + + void AssetGridDialog::SetupDialogButtons() + { + connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(this, &QDialog::rejected, this, [this](){ SelectInitialAsset(); }); + } + + void AssetGridDialog::ApplySearchFilter() + { + for (int index = 0; index < m_ui->m_assetList->count(); ++index) + { + QListWidgetItem* item = m_ui->m_assetList->item(index); + const QString& title = item->data(Qt::DisplayRole).toString(); + const QString filter = m_ui->m_searchWidget->text(); + item->setHidden(!filter.isEmpty() && !title.contains(filter, Qt::CaseInsensitive)); + } + } + + void AssetGridDialog::ShowSearchMenu(const QPoint& pos) + { + QScopedPointer menu(m_ui->m_searchWidget->createStandardContextMenu()); + menu->setStyleSheet("background-color: #333333"); + menu->exec(m_ui->m_searchWidget->mapToGlobal(pos)); + } + + void AssetGridDialog::SelectCurrentAsset() + { + auto item = m_ui->m_assetList->currentItem(); + if (item) + { + AZ::Data::AssetId assetId = AZ::Data::AssetId::CreateString(item->data(Qt::UserRole).toString().toUtf8().constData()); + emit AssetSelected(assetId); + } + } + + void AssetGridDialog::SelectInitialAsset() + { + emit AssetSelected(m_initialSelectedAsset); + } +} // namespace AtomToolsFramework + +#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.ui similarity index 86% rename from Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.ui index 172feb214c..e821a7443f 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.ui @@ -1,7 +1,7 @@ - PresetBrowserDialog - + AssetGridDialog + 0 @@ -26,7 +26,7 @@ - + diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index 122e070096..db20452036 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -9,6 +9,7 @@ set(FILES Include/AtomToolsFramework/Application/AtomToolsApplication.h Include/AtomToolsFramework/AssetBrowser/AtomToolsAssetBrowser.h + Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h Include/AtomToolsFramework/Communication/LocalServer.h Include/AtomToolsFramework/Communication/LocalSocket.h Include/AtomToolsFramework/Debug/TraceRecorder.h @@ -41,6 +42,8 @@ set(FILES Source/AssetBrowser/AtomToolsAssetBrowser.cpp Source/AssetBrowser/AtomToolsAssetBrowser.qrc Source/AssetBrowser/AtomToolsAssetBrowser.ui + Source/AssetGridDialog/AssetGridDialog.cpp + Source/AssetGridDialog/AssetGridDialog.ui Source/Communication/LocalServer.cpp Source/Communication/LocalSocket.cpp Source/Debug/TraceRecorder.cpp diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp deleted file mode 100644 index cc7a851429..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include - -namespace MaterialEditor -{ - LightingPresetBrowserDialog::LightingPresetBrowserDialog(QWidget* parent) - : PresetBrowserDialog(parent) - { - QSignalBlocker signalBlocker(this); - - setWindowTitle("Lighting Preset Browser"); - - MaterialViewportRequestBus::BroadcastResult(m_initialPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); - - AZ::Render::LightingPresetPtrVector presets; - MaterialViewportRequestBus::BroadcastResult(presets, &MaterialViewportRequestBus::Events::GetLightingPresets); - AZStd::sort(presets.begin(), presets.end(), [](const auto& a, const auto& b) { return a->m_displayName < b->m_displayName; }); - - const int itemSize = aznumeric_cast( - AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/PresetBrowserDialog/LightingItemSize", 180)); - - QListWidgetItem* selectedItem = nullptr; - for (const auto& preset : presets) - { - AZStd::string path; - MaterialViewportRequestBus::BroadcastResult(path, &MaterialViewportRequestBus::Events::GetLightingPresetLastSavePath, preset); - QListWidgetItem* item = CreateListItem( - preset->m_displayName.c_str(), AZ::RPI::AssetUtils::MakeAssetId(path, 0).GetValue(), QSize(itemSize, itemSize)); - - m_listItemToPresetMap[item] = preset; - - if (m_initialPreset == preset) - { - selectedItem = item; - } - } - - if (selectedItem) - { - m_ui->m_presetList->setCurrentItem(selectedItem); - m_ui->m_presetList->scrollToItem(selectedItem); - } - } - - void LightingPresetBrowserDialog::SelectCurrentPreset() - { - auto presetItr = m_listItemToPresetMap.find(m_ui->m_presetList->currentItem()); - if (presetItr != m_listItemToPresetMap.end()) - { - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, presetItr->second); - } - } - - void LightingPresetBrowserDialog::SelectInitialPreset() - { - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, m_initialPreset); - } - -} // namespace MaterialEditor - -#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h deleted file mode 100644 index 68b52b3a98..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#endif - -#include - -namespace MaterialEditor -{ - //! Widget for managing and selecting from a library of preset assets - class LightingPresetBrowserDialog : public PresetBrowserDialog - { - Q_OBJECT - public: - LightingPresetBrowserDialog(QWidget* parent = nullptr); - ~LightingPresetBrowserDialog() = default; - - private: - void SelectCurrentPreset() override; - void SelectInitialPreset() override; - - AZ::Render::LightingPresetPtr m_initialPreset; - AZStd::unordered_map m_listItemToPresetMap; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp deleted file mode 100644 index e16b61d214..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include - -namespace MaterialEditor -{ - ModelPresetBrowserDialog::ModelPresetBrowserDialog(QWidget* parent) - : PresetBrowserDialog(parent) - { - QSignalBlocker signalBlocker(this); - - setWindowTitle("Model Preset Browser"); - - MaterialViewportRequestBus::BroadcastResult(m_initialPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); - - AZ::Render::ModelPresetPtrVector presets; - MaterialViewportRequestBus::BroadcastResult(presets, &MaterialViewportRequestBus::Events::GetModelPresets); - AZStd::sort(presets.begin(), presets.end(), [](const auto& a, const auto& b) { return a->m_displayName < b->m_displayName; }); - - const int itemSize = aznumeric_cast( - AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/PresetBrowserDialog/ModelItemSize", 90)); - - QListWidgetItem* selectedItem = nullptr; - for (const auto& preset : presets) - { - QListWidgetItem* item = CreateListItem(preset->m_displayName.c_str(), preset->m_modelAsset.GetId(), QSize(itemSize, itemSize)); - - m_listItemToPresetMap[item] = preset; - - if (m_initialPreset == preset) - { - selectedItem = item; - } - } - - if (selectedItem) - { - m_ui->m_presetList->setCurrentItem(selectedItem); - m_ui->m_presetList->scrollToItem(selectedItem); - } - } - - void ModelPresetBrowserDialog::SelectCurrentPreset() - { - auto presetItr = m_listItemToPresetMap.find(m_ui->m_presetList->currentItem()); - if (presetItr != m_listItemToPresetMap.end()) - { - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, presetItr->second); - } - } - - void ModelPresetBrowserDialog::SelectInitialPreset() - { - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, m_initialPreset); - } - -} // namespace MaterialEditor - -#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h deleted file mode 100644 index a169d3053b..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#endif - -#include - -namespace MaterialEditor -{ - //! Widget for managing and selecting from a library of preset assets - class ModelPresetBrowserDialog : public PresetBrowserDialog - { - Q_OBJECT - public: - ModelPresetBrowserDialog(QWidget* parent = nullptr); - ~ModelPresetBrowserDialog() = default; - - private: - void SelectCurrentPreset() override; - void SelectInitialPreset() override; - - AZ::Render::ModelPresetPtr m_initialPreset; - AZStd::unordered_map m_listItemToPresetMap; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp deleted file mode 100644 index f2bb84dff6..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace MaterialEditor -{ - PresetBrowserDialog::PresetBrowserDialog(QWidget* parent) - : QDialog(parent) - , m_ui(new Ui::PresetBrowserDialog) - { - m_ui->setupUi(this); - - QSignalBlocker signalBlocker(this); - - SetupPresetList(); - SetupSearchWidget(); - SetupDialogButtons(); - setModal(true); - } - - void PresetBrowserDialog::SetupPresetList() - { - m_ui->m_presetList->setFlow(QListView::LeftToRight); - m_ui->m_presetList->setResizeMode(QListView::Adjust); - m_ui->m_presetList->setGridSize(QSize(0, 0)); - m_ui->m_presetList->setWrapping(true); - - QObject::connect(m_ui->m_presetList, &QListWidget::currentItemChanged, [this](){ SelectCurrentPreset(); }); - } - - QListWidgetItem* PresetBrowserDialog::CreateListItem(const QString& title, const AZ::Data::AssetId& assetId, const QSize& size) - { - const int itemBorder = aznumeric_cast( - AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/PresetBrowserDialog/ItemBorder", 4)); - const int itemSpacing = aznumeric_cast( - AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/PresetBrowserDialog/ItemSpacing", 10)); - const int headerHeight = aznumeric_cast( - AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/PresetBrowserDialog/HeaderHeight", 15)); - - const QSize gridSize = m_ui->m_presetList->gridSize(); - m_ui->m_presetList->setGridSize(QSize( - AZStd::max(gridSize.width(), size.width() + itemSpacing), - AZStd::max(gridSize.height(), size.height() + itemSpacing + headerHeight))); - - QListWidgetItem* item = new QListWidgetItem(m_ui->m_presetList); - item->setData(Qt::UserRole, title); - item->setSizeHint(size + QSize(itemBorder, itemBorder + headerHeight)); - m_ui->m_presetList->addItem(item); - - QWidget* itemWidget = new QWidget(m_ui->m_presetList); - itemWidget->setLayout(new QVBoxLayout(itemWidget)); - itemWidget->layout()->setSpacing(0); - itemWidget->layout()->setMargin(0); - - AzQtComponents::ElidingLabel* header = new AzQtComponents::ElidingLabel(itemWidget); - header->setText(title); - header->setFixedSize(QSize(size.width(), headerHeight)); - header->setMargin(0); - header->setStyleSheet("background-color: rgb(35, 35, 35)"); - AzQtComponents::Text::addPrimaryStyle(header); - AzQtComponents::Text::addLabelStyle(header); - itemWidget->layout()->addWidget(header); - - AzToolsFramework::Thumbnailer::ThumbnailWidget* thumbnail = new AzToolsFramework::Thumbnailer::ThumbnailWidget(itemWidget); - thumbnail->setFixedSize(size); - thumbnail->SetThumbnailKey( - MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, assetId), - AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext); - thumbnail->updateGeometry(); - itemWidget->layout()->addWidget(thumbnail); - - m_ui->m_presetList->setItemWidget(item, itemWidget); - - return item; - } - - void PresetBrowserDialog::SetupSearchWidget() - { - m_ui->m_searchWidget->setReadOnly(false); - m_ui->m_searchWidget->setContextMenuPolicy(Qt::CustomContextMenu); - AzQtComponents::LineEdit::applySearchStyle(m_ui->m_searchWidget); - connect(m_ui->m_searchWidget, &QLineEdit::textChanged, this, [this](){ ApplySearchFilter(); }); - connect(m_ui->m_searchWidget, &QWidget::customContextMenuRequested, this, [this](const QPoint& pos){ ShowSearchMenu(pos); }); - } - - void PresetBrowserDialog::SetupDialogButtons() - { - connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(this, &QDialog::rejected, this, [this](){ SelectInitialPreset(); }); - } - - void PresetBrowserDialog::ApplySearchFilter() - { - for (int index = 0; index < m_ui->m_presetList->count(); ++index) - { - QListWidgetItem* item = m_ui->m_presetList->item(index); - const QString& title = item->data(Qt::UserRole).toString(); - const QString filter = m_ui->m_searchWidget->text(); - item->setHidden(!filter.isEmpty() && !title.contains(filter, Qt::CaseInsensitive)); - } - } - - void PresetBrowserDialog::ShowSearchMenu(const QPoint& pos) - { - QScopedPointer menu(m_ui->m_searchWidget->createStandardContextMenu()); - menu->setStyleSheet("background-color: #333333"); - menu->exec(m_ui->m_searchWidget->mapToGlobal(pos)); - } -} // namespace MaterialEditor - -#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h deleted file mode 100644 index 20e049f6f8..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#endif - -#include - -class QImage; -class QListWidgetItem; -class QString; - -namespace MaterialEditor -{ - //! Widget for managing and selecting from a library of preset assets - class PresetBrowserDialog : public QDialog - { - Q_OBJECT - public: - PresetBrowserDialog(QWidget* parent = nullptr); - ~PresetBrowserDialog() = default; - -protected: - void SetupPresetList(); - QListWidgetItem* CreateListItem(const QString& title, const AZ::Data::AssetId& assetId, const QSize& size); - - void SetupSearchWidget(); - void SetupDialogButtons(); - void ApplySearchFilter(); - void ShowSearchMenu(const QPoint& pos); - virtual void SelectCurrentPreset() = 0; - virtual void SelectInitialPreset() = 0; - - QScopedPointer m_ui; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp index 512059f1f6..dd01492031 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp @@ -6,13 +6,15 @@ * */ -#include +#include +#include +#include +#include #include #include #include +#include #include -#include -#include #include #include @@ -110,17 +112,53 @@ namespace MaterialEditor if (!savePath.empty()) { - AZ::Render::ModelPresetPtr preset; - MaterialViewportRequestBus::BroadcastResult( - preset, &MaterialViewportRequestBus::Events::AddModelPreset, AZ::Render::ModelPreset()); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SaveModelPreset, preset, savePath); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, preset); + MaterialViewportRequestBus::Broadcast( + [&savePath](MaterialViewportRequestBus::Events* viewportRequests) + { + AZ::Render::ModelPresetPtr preset = viewportRequests->AddModelPreset(AZ::Render::ModelPreset()); + viewportRequests->SaveModelPreset(preset, savePath); + viewportRequests->SelectModelPreset(preset); + }); } } void ViewportSettingsInspector::SelectModelPreset() { - ModelPresetBrowserDialog dialog(QApplication::activeWindow()); + AZ::Data::AssetId selectedAsset; + AtomToolsFramework::AssetGridDialog::SelectableAssetVector selectableAssets; + AZStd::unordered_map assetIdToPresetMap; + MaterialViewportRequestBus::Broadcast( + [&](MaterialViewportRequestBus::Events* viewportRequests) + { + const auto& selectedPreset = viewportRequests->GetModelPresetSelection(); + selectedAsset = selectedPreset->m_modelAsset.GetId(); + + const auto& presets = viewportRequests->GetModelPresets(); + selectableAssets.reserve(presets.size()); + for (const auto& preset : presets) + { + const auto& presetAssetId = preset->m_modelAsset.GetId(); + selectableAssets.push_back({ presetAssetId, preset->m_displayName.c_str() }); + assetIdToPresetMap[presetAssetId] = preset; + } + }); + + const int itemSize = aznumeric_cast( + AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/AssetGridDialog/ModelItemSize", 180)); + + AtomToolsFramework::AssetGridDialog dialog( + "Model Preset Browser", selectableAssets, selectedAsset, QSize(itemSize, itemSize), QApplication::activeWindow()); + + connect( + &dialog, &AtomToolsFramework::AssetGridDialog::AssetSelected, this, + [assetIdToPresetMap](const AZ::Data::AssetId& assetId) + { + const auto presetItr = assetIdToPresetMap.find(assetId); + if (presetItr != assetIdToPresetMap.end()) + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, presetItr->second); + } + }); dialog.setFixedSize(800, 400); dialog.show(); @@ -198,17 +236,55 @@ namespace MaterialEditor if (!savePath.empty()) { - AZ::Render::LightingPresetPtr preset; - MaterialViewportRequestBus::BroadcastResult( - preset, &MaterialViewportRequestBus::Events::AddLightingPreset, AZ::Render::LightingPreset()); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SaveLightingPreset, preset, savePath); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, preset); + MaterialViewportRequestBus::Broadcast( + [&savePath](MaterialViewportRequestBus::Events* viewportRequests) + { + AZ::Render::LightingPresetPtr preset = viewportRequests->AddLightingPreset(AZ::Render::LightingPreset()); + viewportRequests->SaveLightingPreset(preset, savePath); + viewportRequests->SelectLightingPreset(preset); + }); } } void ViewportSettingsInspector::SelectLightingPreset() { - LightingPresetBrowserDialog dialog(QApplication::activeWindow()); + AZ::Data::AssetId selectedAsset; + AtomToolsFramework::AssetGridDialog::SelectableAssetVector selectableAssets; + AZStd::unordered_map assetIdToPresetMap; + MaterialViewportRequestBus::Broadcast( + [&](MaterialViewportRequestBus::Events* viewportRequests) + { + const auto& selectedPreset = viewportRequests->GetLightingPresetSelection(); + const auto& selectedPresetPath = viewportRequests->GetLightingPresetLastSavePath(selectedPreset); + selectedAsset = AZ::RPI::AssetUtils::MakeAssetId(selectedPresetPath, 0).GetValue(); + + const auto& presets = viewportRequests->GetLightingPresets(); + selectableAssets.reserve(presets.size()); + for (const auto& preset : presets) + { + const auto& path = viewportRequests->GetLightingPresetLastSavePath(preset); + const auto& presetAssetId = AZ::RPI::AssetUtils::MakeAssetId(path, 0).GetValue(); + selectableAssets.push_back({ presetAssetId, preset->m_displayName.c_str() }); + assetIdToPresetMap[presetAssetId] = preset; + } + }); + + const int itemSize = aznumeric_cast( + AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/AssetGridDialog/LightingItemSize", 180)); + + AtomToolsFramework::AssetGridDialog dialog( + "Lighting Preset Browser", selectableAssets, selectedAsset, QSize(itemSize, itemSize), QApplication::activeWindow()); + + connect( + &dialog, &AtomToolsFramework::AssetGridDialog::AssetSelected, this, + [assetIdToPresetMap](const AZ::Data::AssetId& assetId) + { + const auto presetItr = assetIdToPresetMap.find(assetId); + if (presetItr != assetIdToPresetMap.end()) + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, presetItr->second); + } + }); dialog.setFixedSize(800, 400); dialog.show(); @@ -249,20 +325,18 @@ namespace MaterialEditor void ViewportSettingsInspector::Reset() { m_modelPreset.reset(); - MaterialViewportRequestBus::BroadcastResult(m_modelPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); - m_lightingPreset.reset(); - MaterialViewportRequestBus::BroadcastResult(m_lightingPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); - - MaterialViewportRequestBus::BroadcastResult(m_viewportSettings->m_enableGrid, &MaterialViewportRequestBus::Events::GetGridEnabled); - MaterialViewportRequestBus::BroadcastResult( - m_viewportSettings->m_enableShadowCatcher, &MaterialViewportRequestBus::Events::GetShadowCatcherEnabled); - MaterialViewportRequestBus::BroadcastResult( - m_viewportSettings->m_enableAlternateSkybox, &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled); - MaterialViewportRequestBus::BroadcastResult( - m_viewportSettings->m_fieldOfView, &MaterialViewportRequestBus::Handler::GetFieldOfView); - MaterialViewportRequestBus::BroadcastResult( - m_viewportSettings->m_displayMapperOperationType, &MaterialViewportRequestBus::Handler::GetDisplayMapperOperationType); + MaterialViewportRequestBus::Broadcast( + [this](MaterialViewportRequestBus::Events* viewportRequests) + { + m_modelPreset = viewportRequests->GetModelPresetSelection(); + m_lightingPreset = viewportRequests->GetLightingPresetSelection(); + m_viewportSettings->m_enableGrid = viewportRequests->GetGridEnabled(); + m_viewportSettings->m_enableShadowCatcher = viewportRequests->GetShadowCatcherEnabled(); + m_viewportSettings->m_enableAlternateSkybox = viewportRequests->GetAlternateSkyboxEnabled(); + m_viewportSettings->m_fieldOfView = viewportRequests->GetFieldOfView(); + m_viewportSettings->m_displayMapperOperationType = viewportRequests->GetDisplayMapperOperationType(); + }); AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); AtomToolsFramework::InspectorWidget::Reset(); @@ -335,14 +409,16 @@ namespace MaterialEditor { MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnLightingPresetChanged, m_lightingPreset); MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnModelPresetChanged, m_modelPreset); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SetGridEnabled, m_viewportSettings->m_enableGrid); + MaterialViewportRequestBus::Broadcast( - &MaterialViewportRequestBus::Events::SetShadowCatcherEnabled, m_viewportSettings->m_enableShadowCatcher); - MaterialViewportRequestBus::Broadcast( - &MaterialViewportRequestBus::Events::SetAlternateSkyboxEnabled, m_viewportSettings->m_enableAlternateSkybox); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Handler::SetFieldOfView, m_viewportSettings->m_fieldOfView); - MaterialViewportRequestBus::Broadcast( - &MaterialViewportRequestBus::Handler::SetDisplayMapperOperationType, m_viewportSettings->m_displayMapperOperationType); + [this](MaterialViewportRequestBus::Events* viewportRequests) + { + viewportRequests->SetGridEnabled(m_viewportSettings->m_enableGrid); + viewportRequests->SetShadowCatcherEnabled(m_viewportSettings->m_enableShadowCatcher); + viewportRequests->SetAlternateSkyboxEnabled(m_viewportSettings->m_enableAlternateSkybox); + viewportRequests->SetFieldOfView(m_viewportSettings->m_fieldOfView); + viewportRequests->SetDisplayMapperOperationType(m_viewportSettings->m_displayMapperOperationType); + }); } AZStd::string ViewportSettingsInspector::GetDefaultUniqueSaveFilePath(const AZStd::string& baseName) const diff --git a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake index 9d1e2b22f8..a655fd8286 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake +++ b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake @@ -69,13 +69,6 @@ set(FILES Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp Source/Window/CreateMaterialDialog/CreateMaterialDialog.h Source/Window/CreateMaterialDialog/CreateMaterialDialog.ui - Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp - Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h - Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui - Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp - Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h - Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp - Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h Source/Window/PerformanceMonitor/PerformanceMonitorWidget.ui From d6cf8e24f31d98c23712ded6603427d867089f13 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 23 Jan 2022 12:29:33 -0600 Subject: [PATCH 10/20] =?UTF-8?q?Atom=20Tools:=20Replaced=20custom=20help?= =?UTF-8?q?=20dialog=20with=20generic=20message=20box=20The=20help=20dialo?= =?UTF-8?q?g=20just=20displayed=20some=20HTML=20text.=20The=20message=20bo?= =?UTF-8?q?x=20class=20provided=20by=20Qt=20can=20display=20the=20same=20i?= =?UTF-8?q?nformation=20and=20styling=20without=20additional=20code.=20We?= =?UTF-8?q?=20don=E2=80=99t=20want=20to=20carry=20around=20the=20extra=20c?= =?UTF-8?q?lass=20to=20new=20applications=20based=20off=20of=20this=20one?= =?UTF-8?q?=20or=20port=20to=20ATF.=20A=20simple=20about=20box=20was=20als?= =?UTF-8?q?o=20added=20and=20can=20be=20fleshed=20out=20in=20the=20future.?= =?UTF-8?q?=20Both=20dialogs=20will=20eventually=20need=20to=20be=20update?= =?UTF-8?q?d=20with=20additional=20information.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../Source/Window/HelpDialog/HelpDialog.cpp | 23 ------ .../Source/Window/HelpDialog/HelpDialog.h | 38 ---------- .../Source/Window/HelpDialog/HelpDialog.ui | 71 ------------------- .../Source/Window/MaterialEditorWindow.cpp | 20 +++++- .../Code/Source/Window/MaterialEditorWindow.h | 1 + .../Code/materialeditor_files.cmake | 3 - 6 files changed, 18 insertions(+), 138 deletions(-) delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.h delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.ui diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.cpp deleted file mode 100644 index 3e8cf19539..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include - -namespace MaterialEditor -{ - HelpDialog::HelpDialog(QWidget* parent) - : QDialog(parent) - , m_ui(new Ui::HelpDialogWidget) - { - m_ui->setupUi(this); - } - - HelpDialog::~HelpDialog() = default; -} // namespace MaterialEditor - -#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.h deleted file mode 100644 index ec5b756df4..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include - -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include -AZ_POP_DISABLE_WARNING -#endif - -namespace Ui -{ - class HelpDialogWidget; -} - -namespace MaterialEditor -{ - //! Displays help for Material Editor - class HelpDialog - : public QDialog - { - Q_OBJECT - public: - HelpDialog(QWidget* parent = nullptr); - ~HelpDialog(); - - QScopedPointer m_ui; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.ui b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.ui deleted file mode 100644 index 2a2cb06bb2..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.ui +++ /dev/null @@ -1,71 +0,0 @@ - - - HelpDialogWidget - - - - 0 - 0 - 270 - 210 - - - - Material Editor Help - - - - - - <html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Material Editor Controls</span></p><p><span style=" font-weight:600;">LMB</span> - pan camera</p><p><span style=" font-weight:600;">RMB</span> or <span style=" font-weight:600;">Alt+LMB</span> - orbit camera around target</p><p><span style=" font-weight:600;">MMB</span> or <span style=" font-weight:600;">Alt+MMB</span> - move camera on its xy plane</p><p><span style=" font-weight:600;">Alt+RMB</span> or <span style=" font-weight:600;">LMB+RMB</span> - dolly camera on its z axis</p><p><span style=" font-weight:600;">Ctrl+LMB</span> - rotate model</p><p><span style=" font-weight:600;">Shift+LMB</span> - rotate environment</p></body></html> - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Close - - - - - - - - - buttonBox - accepted() - HelpDialogWidget - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - HelpDialogWidget - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp index e1f8e713d4..d538f62e15 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -30,6 +29,7 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnin #include #include #include +#include #include #include AZ_POP_DISABLE_WARNING @@ -178,8 +178,22 @@ namespace MaterialEditor void MaterialEditorWindow::OpenHelp() { - HelpDialog dialog(this); - dialog.exec(); + QMessageBox::information( + this, windowTitle(), + R"( +

Material Editor Controls

+

LMB - pan camera

+

RMB or Alt+LMB - orbit camera around target

+

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

+

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

+

Ctrl+LMB - rotate model

+

Shift+LMB - rotate environment

+ )"); + } + + void MaterialEditorWindow::OpenAbout() + { + QMessageBox::about(this, windowTitle(), QApplication::applicationName()); } void MaterialEditorWindow::closeEvent(QCloseEvent* closeEvent) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h index 8ad294c529..8317382d6d 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h @@ -44,6 +44,7 @@ namespace MaterialEditor bool GetOpenDocumentParams(AZStd::string& openPath) override; void OpenSettings() override; void OpenHelp() override; + void OpenAbout() override; void closeEvent(QCloseEvent* closeEvent) override; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake index 9d1e2b22f8..262f27d854 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake +++ b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake @@ -89,7 +89,4 @@ set(FILES Source/Window/MaterialInspector/MaterialInspector.cpp Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp - Source/Window/HelpDialog/HelpDialog.h - Source/Window/HelpDialog/HelpDialog.cpp - Source/Window/HelpDialog/HelpDialog.ui ) From 0a5f472f4331d5a310e55ac8b9d5dabdc491d079 Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Sat, 22 Jan 2022 14:36:20 +0100 Subject: [PATCH 11/20] Clang 13: Fix build errors ... ... due to local variables only being written to (but never read). Signed-off-by: Daniel Edwards --- Code/Editor/EditorPreferencesPageAWS.cpp | 2 +- Code/Editor/Settings.cpp | 2 +- Code/Editor/ViewPane.cpp | 2 +- Code/Framework/AzCore/AzCore/Math/Matrix3x4.cpp | 6 +++--- Code/Framework/AzCore/AzCore/Math/Uuid.cpp | 2 +- Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp | 2 +- Code/Framework/AzCore/Tests/Name/NameTests.cpp | 2 +- .../AzFramework/Asset/Benchmark/BenchmarkCommands.cpp | 2 +- Code/Framework/AzFramework/Tests/CameraState.cpp | 2 +- .../AzQtComponents/Components/StylesheetPreprocessor.cpp | 2 +- .../AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp | 2 +- .../AzToolsFramework/Prefab/PrefabSystemComponent.cpp | 4 ++-- .../AzToolsFramework/Slice/SliceTransaction.cpp | 2 +- .../UI/PropertyEditor/PropertyEnumComboBoxCtrl.cpp | 2 +- Code/Framework/AzToolsFramework/Tests/Slices.cpp | 2 +- Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp | 4 ++-- .../native/utilities/ApplicationManagerBase.cpp | 2 +- .../AssetProcessor/native/utilities/BuilderManager.inl | 2 +- Code/Tools/ProjectManager/Source/Settings.cpp | 2 +- Code/Tools/SceneAPI/SceneBuilder/Tests/TestsMain.cpp | 2 +- .../Source/Editor/Attribution/AWSCoreAttributionManager.cpp | 2 +- .../AssetValidation/Code/Source/AssetSystemTestCommands.cpp | 6 +++--- .../DiffuseProbeGridFeatureProcessor.cpp | 2 +- .../Code/Source/RayTracing/RayTracingFeatureProcessor.cpp | 2 +- .../ReflectionProbe/ReflectionProbeFeatureProcessor.cpp | 2 +- Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp | 2 +- Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBlas.cpp | 2 +- .../RHI/Vulkan/Code/Source/RHI/RayTracingPipelineState.cpp | 2 +- .../RHI/Vulkan/Code/Source/RHI/RayTracingShaderTable.cpp | 2 +- Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp | 4 ++-- Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp | 2 +- Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 2 +- Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp | 2 +- Gems/EMotionFX/Code/EMotionFX/Source/Recorder.cpp | 2 +- Gems/GraphModel/Code/Source/Model/Node.cpp | 2 +- Gems/GraphModel/Code/Source/Model/Slot.cpp | 2 +- .../LyShine/Code/Editor/PropertyHandlerEntityIdComboBox.cpp | 2 +- .../EntityReplication/EntityReplicationManager.cpp | 2 +- .../Components/ClothComponentMesh/ActorClothColliders.cpp | 4 ++-- .../Source/PhysXCharacters/Components/RagdollComponent.cpp | 2 +- .../NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp | 2 +- .../Code/Source/TerrainRenderer/TerrainMeshManager.cpp | 2 +- 42 files changed, 50 insertions(+), 50 deletions(-) diff --git a/Code/Editor/EditorPreferencesPageAWS.cpp b/Code/Editor/EditorPreferencesPageAWS.cpp index 9279dce7bc..968969245d 100644 --- a/Code/Editor/EditorPreferencesPageAWS.cpp +++ b/Code/Editor/EditorPreferencesPageAWS.cpp @@ -101,7 +101,7 @@ void CEditorPreferencesPage_AWS::SaveSettingsRegistryFile() return; } - bool saved{}; + [[maybe_unused]] bool saved{}; constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPath.data(), configurationMode)) diff --git a/Code/Editor/Settings.cpp b/Code/Editor/Settings.cpp index 8561e6dba3..9514957795 100644 --- a/Code/Editor/Settings.cpp +++ b/Code/Editor/Settings.cpp @@ -1128,7 +1128,7 @@ void SEditorSettings::SaveSettingsRegistryFile() return; } - bool saved{}; + [[maybe_unused]] bool saved{}; constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; diff --git a/Code/Editor/ViewPane.cpp b/Code/Editor/ViewPane.cpp index e3494a4049..90b44d9c9d 100644 --- a/Code/Editor/ViewPane.cpp +++ b/Code/Editor/ViewPane.cpp @@ -745,7 +745,7 @@ namespace void PySetActiveViewport(unsigned int viewportIndex) { - bool success = false; + [[maybe_unused]] bool success = false; CLayoutWnd* layout = GetIEditor()->GetViewManager()->GetLayout(); if (layout) { diff --git a/Code/Framework/AzCore/AzCore/Math/Matrix3x4.cpp b/Code/Framework/AzCore/AzCore/Math/Matrix3x4.cpp index 78da9e76d2..23d0eea618 100644 --- a/Code/Framework/AzCore/AzCore/Math/Matrix3x4.cpp +++ b/Code/Framework/AzCore/AzCore/Math/Matrix3x4.cpp @@ -25,7 +25,7 @@ namespace AZ void Matrix3x4SetRowGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc) { - bool rowIsSet = false; + [[maybe_unused]] bool rowIsSet = false; if (dc.GetNumArguments() >= 5) { if (dc.IsNumber(0)) @@ -88,7 +88,7 @@ namespace AZ void Matrix3x4SetColumnGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc) { - bool columnIsSet = false; + [[maybe_unused]] bool columnIsSet = false; if (dc.GetNumArguments() >= 4) { if (dc.IsNumber(0)) @@ -133,7 +133,7 @@ namespace AZ void Matrix3x4SetTranslationGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc) { - bool translationIsSet = false; + [[maybe_unused]] bool translationIsSet = false; if (dc.GetNumArguments() == 3 && dc.IsNumber(0) && diff --git a/Code/Framework/AzCore/AzCore/Math/Uuid.cpp b/Code/Framework/AzCore/AzCore/Math/Uuid.cpp index 410d235a37..b27f1a0943 100644 --- a/Code/Framework/AzCore/AzCore/Math/Uuid.cpp +++ b/Code/Framework/AzCore/AzCore/Math/Uuid.cpp @@ -77,7 +77,7 @@ namespace AZ // check open brace char c = *current++; - bool has_open_brace = false; + [[maybe_unused]] bool has_open_brace = false; if (c == '{') { c = *current++; diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp index 1b39eb81bd..2bb4faf1d5 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp @@ -85,7 +85,7 @@ namespace AZ NameDictionary::~NameDictionary() { - bool leaksDetected = false; + [[maybe_unused]] bool leaksDetected = false; for (const auto& keyValue : m_dictionary) { diff --git a/Code/Framework/AzCore/Tests/Name/NameTests.cpp b/Code/Framework/AzCore/Tests/Name/NameTests.cpp index eb0a048e2f..9e94c4bfdf 100644 --- a/Code/Framework/AzCore/Tests/Name/NameTests.cpp +++ b/Code/Framework/AzCore/Tests/Name/NameTests.cpp @@ -642,7 +642,7 @@ namespace UnitTest char buffer[RandomStringBufferSize]; AZStd::sys_time_t newNameTime; - AZStd::sys_time_t existingNameTime; + [[maybe_unused]] AZStd::sys_time_t existingNameTime; AZStd::sys_time_t stringTime; { diff --git a/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkCommands.cpp b/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkCommands.cpp index 30c1aa39c0..2c2571ec76 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkCommands.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkCommands.cpp @@ -195,7 +195,7 @@ namespace AzFramework::AssetBenchmark // Console command: Add the given list of assets to the list of assets to load with BenchmarkLoadAssetList void BenchmarkAddAssetsToList(const AZ::ConsoleCommandContainer& parameters) { - bool allAssetsAdded = true; + [[maybe_unused]] bool allAssetsAdded = true; for (auto& assetName : parameters) { diff --git a/Code/Framework/AzFramework/Tests/CameraState.cpp b/Code/Framework/AzFramework/Tests/CameraState.cpp index 1f35d5a06c..974b5dd742 100644 --- a/Code/Framework/AzFramework/Tests/CameraState.cpp +++ b/Code/Framework/AzFramework/Tests/CameraState.cpp @@ -81,7 +81,7 @@ namespace UnitTest TEST_P(Rotation, Permutation) { - int expectedErrors = -1; + [[maybe_unused]] int expectedErrors = -1; AZ_TEST_START_TRACE_SUPPRESSION; // Given an orientation derived from the look at points diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/StylesheetPreprocessor.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/StylesheetPreprocessor.cpp index c334bbb59a..2602ecf535 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/StylesheetPreprocessor.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/StylesheetPreprocessor.cpp @@ -134,7 +134,7 @@ namespace AzQtComponents QColor color; QString colorName(m_namedVariables.value(name)); - bool colorSet = false; + [[maybe_unused]] bool colorSet = false; if (QColor::isValidColor(colorName)) { color.setNamedColor(colorName); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp index 5711ca2608..4aab7288fa 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp @@ -177,7 +177,7 @@ namespace AzToolsFramework auto data = index.data(AssetBrowserModel::Roles::EntryRole); if (data.canConvert()) { - bool isEnabled = (option.state & QStyle::State_Enabled) != 0; + [[maybe_unused]] bool isEnabled = (option.state & QStyle::State_Enabled) != 0; QStyle* style = option.widget ? option.widget->style() : QApplication::style(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 98e0144f22..9648a9af09 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -506,7 +506,7 @@ namespace AzToolsFramework //Remove all Links owned by the Template from TemplateToLinkIdsMap. Template& templateToDelete = findTemplateResult->get(); const Template::Links& linkIdsToDelete = templateToDelete.GetLinks(); - bool result; + [[maybe_unused]] bool result; for (auto linkId : linkIdsToDelete) { result = RemoveLinkIdFromTemplateToLinkIdsMap(linkId); @@ -774,7 +774,7 @@ namespace AzToolsFramework } Link& link = findLinkResult->get(); - bool result; + [[maybe_unused]] bool result; result = RemoveLinkIdFromTemplateToLinkIdsMap(linkId, link); AZ_Assert(result, "Prefab - PrefabSystemComponent::RemoveLink - " diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp index 9d2c58a717..91517bd784 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp @@ -926,7 +926,7 @@ namespace AzToolsFramework const bool entityIsFromIgnoredSliceInstance = ignoreSliceInstance && ignoreSliceInstance->IsValid() && ignoreSliceInstance->GetReference()->GetSliceAsset().GetId() == instanceAddr.GetReference()->GetSliceAsset().GetId(); if (!entityIsFromIgnoredSliceInstance) { - bool foundTargetAncestor = false; + [[maybe_unused]] bool foundTargetAncestor = false; const AZ::SliceComponent::EntityList& entitiesInInstance = instanceAddr.GetInstance()->GetInstantiated()->m_entities; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEnumComboBoxCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEnumComboBoxCtrl.cpp index f49b555dfe..f37fd860ea 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEnumComboBoxCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEnumComboBoxCtrl.cpp @@ -45,7 +45,7 @@ namespace AzToolsFramework void PropertyEnumComboBoxCtrl::setValue(AZ::s64 value) { m_pComboBox->blockSignals(true); - bool indexWasFound = false; + [[maybe_unused]] bool indexWasFound = false; for (size_t enumValIndex = 0; enumValIndex < m_enumValues.size(); enumValIndex++) { if (m_enumValues[enumValIndex].first == value) diff --git a/Code/Framework/AzToolsFramework/Tests/Slices.cpp b/Code/Framework/AzToolsFramework/Tests/Slices.cpp index 9b546357cd..bf59e1f8bd 100644 --- a/Code/Framework/AzToolsFramework/Tests/Slices.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Slices.cpp @@ -430,7 +430,7 @@ namespace UnitTest size_t nextIndex = 1; size_t slices = 0; size_t liveAllocs = 0; - size_t totalAllocs = 0; + [[maybe_unused]] size_t totalAllocs = 0; auto cb = [&liveAllocs](void*, const AZ::Debug::AllocationInfo&, unsigned char) { diff --git a/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp b/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp index 2724bee1a7..9d88f26278 100644 --- a/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp +++ b/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp @@ -1952,8 +1952,8 @@ CarrierThread::ProcessConnections() bool isHandshakeTimeOut = false; bool isConnectionTimeout = false; - bool isBadTrafficConditions = false; - bool isBadPackets = false; + [[maybe_unused]] bool isBadTrafficConditions = false; + [[maybe_unused]] bool isBadPackets = false; if (connection->m_isBadPackets) { isBadPackets = true; diff --git a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp index 36450c4e65..634fdbd3bb 100644 --- a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp @@ -544,7 +544,7 @@ void ApplicationManagerBase::InitConnectionManager() EBUS_EVENT(AssetProcessor::ConnectionBus, SendPerPlatform, 0, message, QString::fromUtf8(message.m_platform.c_str())); }; - bool result = QObject::connect(GetAssetCatalog(), &AssetProcessor::AssetCatalog::SendAssetMessage, connectionAndChangeMessagesThreadContext, forwardMessageFunction, Qt::QueuedConnection); + [[maybe_unused]] bool result = QObject::connect(GetAssetCatalog(), &AssetProcessor::AssetCatalog::SendAssetMessage, connectionAndChangeMessagesThreadContext, forwardMessageFunction, Qt::QueuedConnection); AZ_Assert(result, "Failed to connect to AssetCatalog signal"); //Application manager related stuff diff --git a/Code/Tools/AssetProcessor/native/utilities/BuilderManager.inl b/Code/Tools/AssetProcessor/native/utilities/BuilderManager.inl index 039680dfae..4d1983691a 100644 --- a/Code/Tools/AssetProcessor/native/utilities/BuilderManager.inl +++ b/Code/Tools/AssetProcessor/native/utilities/BuilderManager.inl @@ -19,7 +19,7 @@ namespace AssetProcessor TNetResponse netResponse; netRequest.m_request = request; - AZ::u32 type; + [[maybe_unused]] AZ::u32 type; QByteArray data; AZStd::binary_semaphore wait; diff --git a/Code/Tools/ProjectManager/Source/Settings.cpp b/Code/Tools/ProjectManager/Source/Settings.cpp index 0a8b600dd9..78100848b5 100644 --- a/Code/Tools/ProjectManager/Source/Settings.cpp +++ b/Code/Tools/ProjectManager/Source/Settings.cpp @@ -41,7 +41,7 @@ namespace O3DE::ProjectManager o3deUserPath /= AZ::SettingsRegistryInterface::RegistryFolder; o3deUserPath /= "ProjectManager.setreg"; - bool saved = false; + [[maybe_unused]] bool saved = false; constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; diff --git a/Code/Tools/SceneAPI/SceneBuilder/Tests/TestsMain.cpp b/Code/Tools/SceneAPI/SceneBuilder/Tests/TestsMain.cpp index 5c0d2503c0..2b7497951f 100644 --- a/Code/Tools/SceneAPI/SceneBuilder/Tests/TestsMain.cpp +++ b/Code/Tools/SceneAPI/SceneBuilder/Tests/TestsMain.cpp @@ -25,7 +25,7 @@ protected: sceneCoreModule = AZ::DynamicModuleHandle::Create("SceneCore"); AZ_Assert(sceneCoreModule, "SceneBuilder unit tests failed to create SceneCore module."); - bool loaded = sceneCoreModule->Load(false); + [[maybe_unused]] bool loaded = sceneCoreModule->Load(false); AZ_Assert(loaded, "SceneBuilder unit tests failed to load SceneCore module."); auto init = sceneCoreModule->GetFunction(AZ::InitializeDynamicModuleFunctionName); AZ_Assert(init, "SceneBuilder unit tests failed to find the initialization function the SceneCore module."); diff --git a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp index 3b9352d250..c52d3be088 100644 --- a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp +++ b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp @@ -223,7 +223,7 @@ namespace AWSCore return; } - bool saved {}; + [[maybe_unused]] bool saved {}; constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPathAWSPreference.c_str(), configurationMode)) diff --git a/Gems/AssetValidation/Code/Source/AssetSystemTestCommands.cpp b/Gems/AssetValidation/Code/Source/AssetSystemTestCommands.cpp index 18888c7166..2007ac01a9 100644 --- a/Gems/AssetValidation/Code/Source/AssetSystemTestCommands.cpp +++ b/Gems/AssetValidation/Code/Source/AssetSystemTestCommands.cpp @@ -120,9 +120,9 @@ namespace AssetValidation AZ::SimpleLcgRandom randomizer(seedValue); int lastTick = 0; AZStd::vector> heldAssets; - AZStd::size_t heldCount{ 0 }; - AZ::u64 changeCount{ 0 }; - AZ::u64 blockCount{ 0 }; + [[maybe_unused]] AZStd::size_t heldCount{ 0 }; + [[maybe_unused]] AZ::u64 changeCount{ 0 }; + [[maybe_unused]] AZ::u64 blockCount{ 0 }; AZ_TracePrintf("TestChangeAssets", "Beginning run with %zu assets\n", assetList.size()); while (!forceStop && runMs < runTime) { diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index ea02a8e0a2..d690c57dea 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -537,7 +537,7 @@ namespace AZ request.m_buffer = m_boxIndexBuffer.get(); request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, m_boxIndices.size() * sizeof(uint16_t) }; request.m_initialData = m_boxIndices.data(); - AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request); + [[maybe_unused]] AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request); AZ_Error("DiffuseProbeGridFeatureProcessor", result == RHI::ResultCode::Success, "Failed to initialize box index buffer - error [%d]", result); // create index buffer view diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp index 0a9782980f..f5c1be284e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp @@ -123,7 +123,7 @@ namespace AZ // create the BLAS buffers for each sub-mesh, or re-use existing BLAS objects if they were already created. // Note: all sub-meshes must either create new BLAS objects or re-use existing ones, otherwise it's an error (it's the same model in both cases) // Note: the buffer is just reserved here, the BLAS is built in the RayTracingAccelerationStructurePass - bool blasInstanceFound = false; + [[maybe_unused]] bool blasInstanceFound = false; for (uint32_t subMeshIndex = 0; subMeshIndex < mesh.m_subMeshes.size(); ++subMeshIndex) { SubMesh& subMesh = mesh.m_subMeshes[subMeshIndex]; diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp index 0f9356428a..3ff574d977 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp @@ -397,7 +397,7 @@ namespace AZ request.m_buffer = m_boxIndexBuffer.get(); request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, m_boxIndices.size() * sizeof(uint16_t) }; request.m_initialData = m_boxIndices.data(); - AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request); + [[maybe_unused]] AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request); AZ_Error("ReflectionProbeFeatureProcessor", result == RHI::ResultCode::Success, "Failed to initialize box index buffer - error [%d]", result); // create index buffer view diff --git a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp index 79c05c37da..3279372052 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp @@ -364,7 +364,7 @@ namespace AZ AZ_Assert(success, "PipelineStateEntry already exists in the pending cache."); } - ResultCode resultCode = ResultCode::InvalidArgument; + [[maybe_unused]] ResultCode resultCode = ResultCode::InvalidArgument; // Increment the pending compile count on the global entry, which tracks how many pipeline states // are currently being compiled across all threads. diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBlas.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBlas.cpp index a322380fb1..e4a90d0739 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBlas.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBlas.cpp @@ -120,7 +120,7 @@ namespace AZ AZ::RHI::BufferInitRequest scratchBufferRequest; scratchBufferRequest.m_buffer = buffers.m_scratchBuffer.get(); scratchBufferRequest.m_descriptor = scratchBufferDescriptor; - RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest); + [[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest); AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create BLAS scratch buffer"); BufferMemoryView* scratchMemoryView = static_cast(buffers.m_scratchBuffer.get())->GetBufferMemoryView(); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingPipelineState.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingPipelineState.cpp index 65281d923f..bddfb0df5e 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingPipelineState.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingPipelineState.cpp @@ -170,7 +170,7 @@ namespace AZ createInfo.basePipelineHandle = nullptr; createInfo.basePipelineIndex = 0; - VkResult result = vkCreateRayTracingPipelinesKHR(device.GetNativeDevice(), nullptr, nullptr, 1, &createInfo, nullptr, &m_pipeline); + [[maybe_unused]] VkResult result = vkCreateRayTracingPipelinesKHR(device.GetNativeDevice(), nullptr, nullptr, 1, &createInfo, nullptr, &m_pipeline); AZ_Assert(result == VK_SUCCESS, "vkCreateRayTracingPipelinesKHR failed"); // retrieve the shader handles diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingShaderTable.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingShaderTable.cpp index d5ef121875..5e820a18ba 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingShaderTable.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingShaderTable.cpp @@ -43,7 +43,7 @@ namespace AZ AZ::RHI::BufferInitRequest shaderTableBufferRequest; shaderTableBufferRequest.m_buffer = shaderTableBuffer.get(); shaderTableBufferRequest.m_descriptor = shaderTableBufferDescriptor; - RHI::ResultCode resultCode = bufferPools.GetShaderTableBufferPool()->InitBuffer(shaderTableBufferRequest); + [[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetShaderTableBufferPool()->InitBuffer(shaderTableBufferRequest); AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create shader table buffer"); BufferMemoryView* shaderTableMemoryView = static_cast(shaderTableBuffer.get())->GetBufferMemoryView(); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp index 9ea9ceccce..08b933c96b 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp @@ -66,7 +66,7 @@ namespace AZ AZ::RHI::BufferInitRequest tlasInstancesBufferRequest; tlasInstancesBufferRequest.m_buffer = buffers.m_tlasInstancesBuffer.get(); tlasInstancesBufferRequest.m_descriptor = tlasInstancesBufferDescriptor; - RHI::ResultCode resultCode = bufferPools.GetTlasInstancesBufferPool()->InitBuffer(tlasInstancesBufferRequest); + [[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetTlasInstancesBufferPool()->InitBuffer(tlasInstancesBufferRequest); AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create TLAS instances buffer"); BufferMemoryView* tlasInstancesMemoryView = static_cast(buffers.m_tlasInstancesBuffer.get())->GetBufferMemoryView(); @@ -160,7 +160,7 @@ namespace AZ AZ::RHI::BufferInitRequest scratchBufferRequest; scratchBufferRequest.m_buffer = buffers.m_scratchBuffer.get(); scratchBufferRequest.m_descriptor = scratchBufferDescriptor; - RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest); + [[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest); AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create TLAS scratch buffer"); BufferMemoryView* scratchMemoryView = static_cast(buffers.m_scratchBuffer.get())->GetBufferMemoryView(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index bd196a2e2b..41cfb5ff12 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -312,7 +312,7 @@ namespace AZ const View::UsageFlags viewFlags = worklistData->m_view->GetUsageFlags(); const RHI::DrawListMask drawListMask = worklistData->m_view->GetDrawListMask(); - uint32_t numDrawPackets = 0; + [[maybe_unused]] uint32_t numDrawPackets = 0; uint32_t numVisibleCullables = 0; AZ_Assert(worklist.size() > 0, "Received empty worklist in ProcessWorklist"); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 1b5110e327..83ac77a390 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -322,7 +322,7 @@ namespace AZ void Scene::RemoveRenderPipeline(const RenderPipelineId& pipelineId) { - bool removed = false; + [[maybe_unused]] bool removed = false; for (auto it = m_pipelines.begin(); it != m_pipelines.end(); ++it) { if (pipelineId == (*it)->GetId()) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp index 9130636e2a..72d574508f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp @@ -123,7 +123,7 @@ namespace EMotionFX TargetType* targetBuffer = static_cast(targetVertexAttributeLayer->GetData()); // Fill the vertex attribute layer by iterating through the Atom meshes and copying over the vertex data for each. - size_t addedElements = 0; + [[maybe_unused]] size_t addedElements = 0; for (const AZ::RPI::ModelLodAsset::Mesh& atomMesh : sourceModelLod->GetMeshes()) { const uint32_t atomMeshVertexCount = atomMesh.GetVertexCount(); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Recorder.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Recorder.cpp index 54fb130ad3..116026e8c1 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Recorder.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Recorder.cpp @@ -863,7 +863,7 @@ namespace EMotionFX } // process all objects for this frame - size_t totalBytesRead = 0; + [[maybe_unused]] size_t totalBytesRead = 0; const size_t numObjects = frameObjects.size(); for (size_t a = 0; a < numObjects; ++a) { diff --git a/Gems/GraphModel/Code/Source/Model/Node.cpp b/Gems/GraphModel/Code/Source/Model/Node.cpp index f51bd1f617..e55b7c05a4 100644 --- a/Gems/GraphModel/Code/Source/Model/Node.cpp +++ b/Gems/GraphModel/Code/Source/Model/Node.cpp @@ -68,7 +68,7 @@ namespace GraphModel CreateSlotData(m_inputEventSlots, m_inputEventSlotDefinitions); CreateSlotData(m_outputEventSlots, m_outputEventSlotDefinitions); - int numExtendableSlots = 0; + [[maybe_unused]] int numExtendableSlots = 0; for (auto it = m_extendableSlots.begin(); it != m_extendableSlots.end(); it++) { numExtendableSlots += aznumeric_cast(it->second.size()); diff --git a/Gems/GraphModel/Code/Source/Model/Slot.cpp b/Gems/GraphModel/Code/Source/Model/Slot.cpp index 08b52760cb..108067cc93 100644 --- a/Gems/GraphModel/Code/Source/Model/Slot.cpp +++ b/Gems/GraphModel/Code/Source/Model/Slot.cpp @@ -491,7 +491,7 @@ namespace GraphModel // multiple supported types, Slot::GetDataType() will call GetParentNode() // to try and resolve its type, which will be a nullptr at this point // because the parent won't be valid yet - bool valueTypeSupported = false; + [[maybe_unused]] bool valueTypeSupported = false; DataTypePtr valueDataType = GetGraphContext()->GetDataTypeForValue(m_value); for (DataTypePtr dataType : GetSupportedDataTypes()) { diff --git a/Gems/LyShine/Code/Editor/PropertyHandlerEntityIdComboBox.cpp b/Gems/LyShine/Code/Editor/PropertyHandlerEntityIdComboBox.cpp index 9bb98dd575..809803c3a7 100644 --- a/Gems/LyShine/Code/Editor/PropertyHandlerEntityIdComboBox.cpp +++ b/Gems/LyShine/Code/Editor/PropertyHandlerEntityIdComboBox.cpp @@ -156,7 +156,7 @@ PropertyEntityIdComboBoxCtrl::PropertyEntityIdComboBoxCtrl(QWidget* pParent) void PropertyEntityIdComboBoxCtrl::setValue(AZ::EntityId value) { m_pComboBox->blockSignals(true); - bool indexWasFound = false; + [[maybe_unused]] bool indexWasFound = false; for (size_t enumValIndex = 0; enumValIndex < m_enumValues.size(); enumValIndex++) { if (m_enumValues[enumValIndex].first == value) diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp index e095af4ae7..893799a296 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp @@ -1126,7 +1126,7 @@ namespace Multiplayer netBindComponent->NotifyServerMigration(GetRemoteHostId()); } - bool didSucceed = true; + [[maybe_unused]] bool didSucceed = true; EntityMigrationMessage message; message.m_netEntityId = replicator->GetEntityHandle().GetNetEntityId(); message.m_prefabEntityId = netBindComponent->GetPrefabEntityId(); diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.cpp b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.cpp index 1e57999b6e..cde8740694 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.cpp +++ b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.cpp @@ -72,8 +72,8 @@ namespace NvCloth // Maximum number of spheres and capsules is imposed by NvCloth library size_t sphereCount = 0; size_t capsuleCount = 0; - bool maxSphereCountReachedWarned = false; - bool maxCapsuleCountReachedWarned = false; + [[maybe_unused]] bool maxSphereCountReachedWarned = false; + [[maybe_unused]] bool maxCapsuleCountReachedWarned = false; AZStd::vector sphereColliders; AZStd::vector capsuleColliders; diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp index 7615a175d1..2c00fd188d 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp @@ -422,7 +422,7 @@ namespace PhysX return d1.m_depth < d2.m_depth; }); - bool massesClamped = false; + [[maybe_unused]] bool massesClamped = false; for (const auto& nodeDepth : nodeDepths) { const size_t nodeIndex = nodeDepth.m_index; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp index da0e9c6045..86fdc0342b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp @@ -145,7 +145,7 @@ namespace ScriptCanvasEditor ScriptEvents::ScriptEventsAsset* data = asset.GetAs(); if (data) { - const ScriptEvents::ScriptEvent* previousDefinition = nullptr; + [[maybe_unused]] const ScriptEvents::ScriptEvent* previousDefinition = nullptr; ScriptEvents::ScriptEventsAsset* previousData = m_asset.GetAs(); if (previousData) { diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMeshManager.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMeshManager.cpp index d689d2635c..4a0d260a74 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMeshManager.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMeshManager.cpp @@ -291,7 +291,7 @@ namespace Terrain modelAssetCreator.Begin(AZ::Uuid::CreateRandom()); uint16_t gridSize = GridSize; - float gridSpacing = GridSpacing; + [[maybe_unused]] float gridSpacing = GridSpacing; for (uint32_t i = 0; i < AZ::RPI::ModelLodAsset::LodCountMax && gridSize > 0; ++i) { From aabde7916fde25177c737c199c9cb8ee94ae2753 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 23 Jan 2022 16:25:57 -0600 Subject: [PATCH 12/20] Atom Tools: Combined ME viewport widget and renderer classes Was looking into options for making any part of this more generic or reusable but 60% of the code is just setup and teardown of processors, handles, entities, and components for the material editor viewport content. The rest is about handling material editors specific setting changes. Most of the general-purpose code has already been moved into atom tools framework render viewport widget. The best reduction or generalization from this point would be using prefabs or some other mechanism to data drive setting up camera, viewport model, IBL, lighting, sky box. Also discussing options for replacing the material editor viewport camera controller and states with a generic one used in the main editor and animation editor. Signed-off-by: Guthrie Adams --- .../Viewport/MaterialViewportRenderer.cpp | 462 ------------------ .../Viewport/MaterialViewportRenderer.h | 114 ----- .../Viewport/MaterialViewportWidget.cpp | 458 ++++++++++++++++- .../Source/Viewport/MaterialViewportWidget.h | 97 +++- .../Code/materialeditor_files.cmake | 2 - 5 files changed, 536 insertions(+), 597 deletions(-) delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp deleted file mode 100644 index 478fb92c55..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#undef RC_INVOKED - -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace MaterialEditor -{ - static constexpr float DepthNear = 0.01f; - - MaterialViewportRenderer::MaterialViewportRenderer(AZStd::shared_ptr windowContext) - : m_windowContext(windowContext) - , m_viewportController(AZStd::make_shared()) - { - using namespace AZ; - using namespace Data; - - // Create and register a scene with all available feature processors - AZ::RPI::SceneDescriptor sceneDesc; - sceneDesc.m_nameId = AZ::Name("MaterialViewport"); - m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); - m_scene->EnableAllFeatureProcessors(); - - // Bind m_defaultScene to the GameEntityContext's AzFramework::Scene - auto sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "MaterialViewportRenderer was unable to get the scene system during construction."); - AZStd::shared_ptr mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName); - - // This should never happen unless scene creation has changed. - AZ_Assert(mainScene, "Main scenes missing during system component initialization"); - mainScene->SetSubsystem(m_scene); - - // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene - AZ::Data::Asset pipelineAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath(m_defaultPipelineAssetPath.c_str(), AZ::RPI::AssetUtils::TraceLevel::Error); - m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineAsset, *m_windowContext.get()); - pipelineAsset.Release(); - m_scene->AddRenderPipeline(m_renderPipeline); - - // As part of our initialization we need to create the BRDF texture generation pipeline - AZ::RPI::RenderPipelineDescriptor pipelineDesc; - pipelineDesc.m_mainViewTagName = "MainCamera"; - pipelineDesc.m_name = "BRDFTexturePipeline"; - pipelineDesc.m_rootPassTemplate = "BRDFTexturePipeline"; - pipelineDesc.m_executeOnce = true; - - AZ::RPI::RenderPipelinePtr brdfTexturePipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); - m_scene->AddRenderPipeline(brdfTexturePipeline); - - // Currently the scene has to be activated after render pipeline was added so some feature processors (i.e. imgui) can be initialized properly - // with pipeline's pass information. - m_scene->Activate(); - - AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); - - AzFramework::EntityContextId entityContextId; - AzFramework::GameEntityContextRequestBus::BroadcastResult(entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId); - - // Configure camera - AzFramework::EntityContextRequestBus::EventResult(m_cameraEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "Cameraentity"); - AZ_Assert(m_cameraEntity != nullptr, "Failed to create camera entity."); - - //Add debug camera and controller components - AZ::Debug::CameraComponentConfig cameraConfig(m_windowContext); - cameraConfig.m_fovY = AZ::Constants::HalfPi; - cameraConfig.m_depthNear = DepthNear; - m_cameraComponent = m_cameraEntity->CreateComponent(azrtti_typeid()); - m_cameraComponent->SetConfiguration(cameraConfig); - m_cameraEntity->CreateComponent(azrtti_typeid()); - m_cameraEntity->Activate(); - - // Connect camera to pipeline's default view after camera entity activated - m_renderPipeline->SetDefaultViewFromEntity(m_cameraEntity->GetId()); - - // Configure tone mapper - AzFramework::EntityContextRequestBus::EventResult(m_postProcessEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "postProcessEntity"); - AZ_Assert(m_postProcessEntity != nullptr, "Failed to create post process entity."); - - m_postProcessEntity->CreateComponent(AZ::Render::PostFxLayerComponentTypeId); - m_postProcessEntity->CreateComponent(AZ::Render::ExposureControlComponentTypeId); - m_postProcessEntity->CreateComponent(azrtti_typeid()); - m_postProcessEntity->Activate(); - - // Init directional light processor - m_directionalLightFeatureProcessor = m_scene->GetFeatureProcessor(); - - // Init display mapper processor - m_displayMapperFeatureProcessor = m_scene->GetFeatureProcessor(); - - // Init Skybox - m_skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); - m_skyboxFeatureProcessor->Enable(true); - m_skyboxFeatureProcessor->SetSkyboxMode(AZ::Render::SkyBoxMode::Cubemap); - - // Create IBL - AzFramework::EntityContextRequestBus::EventResult(m_iblEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "IblEntity"); - AZ_Assert(m_iblEntity != nullptr, "Failed to create ibl entity."); - - m_iblEntity->CreateComponent(Render::ImageBasedLightComponentTypeId); - m_iblEntity->CreateComponent(azrtti_typeid()); - m_iblEntity->Activate(); - - // Create model - AzFramework::EntityContextRequestBus::EventResult(m_modelEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); - AZ_Assert(m_modelEntity != nullptr, "Failed to create model entity."); - - m_modelEntity->CreateComponent(AZ::Render::MeshComponentTypeId); - m_modelEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); - m_modelEntity->CreateComponent(azrtti_typeid()); - m_modelEntity->Activate(); - - // Create shadow catcher - AzFramework::EntityContextRequestBus::EventResult(m_shadowCatcherEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportShadowCatcher"); - AZ_Assert(m_shadowCatcherEntity != nullptr, "Failed to create shadow catcher entity."); - m_shadowCatcherEntity->CreateComponent(AZ::Render::MeshComponentTypeId); - m_shadowCatcherEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); - m_shadowCatcherEntity->CreateComponent(azrtti_typeid()); - m_shadowCatcherEntity->CreateComponent(azrtti_typeid()); - m_shadowCatcherEntity->Activate(); - - AZ::NonUniformScaleRequestBus::Event(m_shadowCatcherEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, AZ::Vector3{ 100, 100, 1.0 }); - - AZ::Data::AssetId shadowCatcherModelAssetId = RPI::AssetUtils::GetAssetIdForProductPath("materialeditor/viewportmodels/plane_1x1.azmodel", RPI::AssetUtils::TraceLevel::Error); - AZ::Render::MeshComponentRequestBus::Event(m_shadowCatcherEntity->GetId(), - &AZ::Render::MeshComponentRequestBus::Events::SetModelAssetId, shadowCatcherModelAssetId); - - auto shadowCatcherMaterialAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath("materials/special/shadowcatcher.azmaterial", RPI::AssetUtils::TraceLevel::Error); - if (shadowCatcherMaterialAsset) - { - m_shadowCatcherOpacityPropertyIndex = shadowCatcherMaterialAsset->GetMaterialTypeAsset()->GetMaterialPropertiesLayout()->FindPropertyIndex(AZ::Name{ "settings.opacity" }); - AZ_Error("MaterialViewportRenderer", m_shadowCatcherOpacityPropertyIndex.IsValid(), "Could not find opacity property"); - - m_shadowCatcherMaterial = AZ::RPI::Material::Create(shadowCatcherMaterialAsset); - AZ_Error("MaterialViewportRenderer", m_shadowCatcherMaterial != nullptr, "Could not create shadow catcher material."); - - AZ::Render::MaterialAssignmentMap shadowCatcherMaterials; - auto& shadowCatcherMaterialAssignment = shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId]; - shadowCatcherMaterialAssignment.m_materialInstance = m_shadowCatcherMaterial; - shadowCatcherMaterialAssignment.m_materialInstancePreCreated = true; - - AZ::Render::MaterialComponentRequestBus::Event(m_shadowCatcherEntity->GetId(), - &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, shadowCatcherMaterials); - } - - // Create grid - AzFramework::EntityContextRequestBus::EventResult(m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid"); - AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity."); - - AZ::Render::GridComponentConfig gridConfig; - gridConfig.m_gridSize = 4.0f; - gridConfig.m_axisColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); - gridConfig.m_primaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); - gridConfig.m_secondaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); - auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId); - gridComponent->SetConfiguration(gridConfig); - - m_gridEntity->CreateComponent(azrtti_typeid()); - m_gridEntity->Activate(); - - OnDocumentOpened(AZ::Uuid::CreateNull()); - - // Attempt to apply the default lighting preset - AZ::Render::LightingPresetPtr lightingPreset; - MaterialViewportRequestBus::BroadcastResult(lightingPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); - OnLightingPresetSelected(lightingPreset); - - // Attempt to apply the default model preset - AZ::Render::ModelPresetPtr modelPreset; - MaterialViewportRequestBus::BroadcastResult(modelPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); - OnModelPresetSelected(modelPreset); - - m_viewportController->Init(m_cameraEntity->GetId(), m_modelEntity->GetId(), m_iblEntity->GetId()); - - // Apply user settinngs restored since last run - AZStd::intrusive_ptr viewportSettings = - AZ::UserSettings::CreateFind(AZ::Crc32("MaterialViewportSettings"), AZ::UserSettings::CT_GLOBAL); - - OnGridEnabledChanged(viewportSettings->m_enableGrid); - OnShadowCatcherEnabledChanged(viewportSettings->m_enableShadowCatcher); - OnAlternateSkyboxEnabledChanged(viewportSettings->m_enableAlternateSkybox); - OnFieldOfViewChanged(viewportSettings->m_fieldOfView); - OnDisplayMapperOperationTypeChanged(viewportSettings->m_displayMapperOperationType); - - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); - MaterialViewportNotificationBus::Handler::BusConnect(); - AZ::TickBus::Handler::BusConnect(); - AZ::TransformNotificationBus::MultiHandler::BusConnect(m_cameraEntity->GetId()); - } - - MaterialViewportRenderer::~MaterialViewportRenderer() - { - AZ::TransformNotificationBus::MultiHandler::BusDisconnect(); - AZ::TickBus::Handler::BusDisconnect(); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); - MaterialViewportNotificationBus::Handler::BusDisconnect(); - AZ::Data::AssetBus::Handler::BusDisconnect(); - - AzFramework::EntityContextId entityContextId; - AzFramework::GameEntityContextRequestBus::BroadcastResult(entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId); - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_iblEntity); - m_iblEntity = nullptr; - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); - m_modelEntity = nullptr; - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_shadowCatcherEntity); - m_shadowCatcherEntity = nullptr; - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_gridEntity); - m_gridEntity = nullptr; - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_cameraEntity); - m_cameraEntity = nullptr; - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_postProcessEntity); - m_postProcessEntity = nullptr; - - for (DirectionalLightHandle& handle : m_lightHandles) - { - m_directionalLightFeatureProcessor->ReleaseLight(handle); - } - m_lightHandles.clear(); - - auto sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "MaterialViewportRenderer was unable to get the scene system during destruction."); - AZStd::shared_ptr mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName); - // This should never happen unless scene creation has changed. - AZ_Assert(mainScene, "Main scenes missing during system component destruction"); - mainScene->UnsetSubsystem(m_scene); - - m_swapChainPass = nullptr; - AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); - m_scene = nullptr; - } - - AZStd::shared_ptr MaterialViewportRenderer::GetController() - { - return m_viewportController; - } - - void MaterialViewportRenderer::OnDocumentOpened(const AZ::Uuid& documentId) - { - AZ::Data::Instance materialInstance; - MaterialDocumentRequestBus::EventResult(materialInstance, documentId, &MaterialDocumentRequestBus::Events::GetInstance); - - AZ::Render::MaterialAssignmentMap materials; - auto& materialAssignment = materials[AZ::Render::DefaultMaterialAssignmentId]; - materialAssignment.m_materialInstance = materialInstance; - materialAssignment.m_materialInstancePreCreated = true; - - AZ::Render::MaterialComponentRequestBus::Event(m_modelEntity->GetId(), - &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, materials); - } - - void MaterialViewportRenderer::OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset) - { - if (!preset) - { - return; - } - - AZ::Render::ImageBasedLightFeatureProcessorInterface* iblFeatureProcessor = m_scene->GetFeatureProcessor(); - AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); - - AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId())->GetOrCreateExposureControlSettingsInterface(); - - Camera::Configuration cameraConfig; - Camera::CameraRequestBus::EventResult(cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); - - bool enableAlternateSkybox = false; - MaterialViewportRequestBus::BroadcastResult(enableAlternateSkybox, &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled); - - preset->ApplyLightingPreset( - iblFeatureProcessor, - m_skyboxFeatureProcessor, - exposureControlSettingInterface, - m_directionalLightFeatureProcessor, - cameraConfig, - m_lightHandles, - m_shadowCatcherMaterial, - m_shadowCatcherOpacityPropertyIndex, - enableAlternateSkybox); - } - - void MaterialViewportRenderer::OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) - { - AZ::Render::LightingPresetPtr selectedPreset; - MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); - if (selectedPreset == preset) - { - OnLightingPresetSelected(preset); - } - } - - void MaterialViewportRenderer::OnModelPresetSelected(AZ::Render::ModelPresetPtr preset) - { - if (!preset) - { - return; - } - - if (!preset->m_modelAsset.GetId().IsValid()) - { - AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid model for preset: '%s'\n.", preset->m_displayName.c_str()); - return; - } - - if (preset->m_modelAsset.GetId() == m_modelAssetId) - { - return; - } - - AZ::Render::MeshComponentRequestBus::Event(m_modelEntity->GetId(), - &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, preset->m_modelAsset); - - m_modelAssetId = preset->m_modelAsset.GetId(); - - AZ::Data::AssetBus::Handler::BusDisconnect(); - AZ::Data::AssetBus::Handler::BusConnect(m_modelAssetId); - } - - void MaterialViewportRenderer::OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) - { - AZ::Render::ModelPresetPtr selectedPreset; - MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); - if (selectedPreset == preset) - { - OnModelPresetSelected(preset); - } - } - - void MaterialViewportRenderer::OnShadowCatcherEnabledChanged(bool enable) - { - AZ::Render::MeshComponentRequestBus::Event(m_shadowCatcherEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetVisibility, enable); - } - - void MaterialViewportRenderer::OnGridEnabledChanged(bool enable) - { - if (m_gridEntity) - { - if (enable && m_gridEntity->GetState() == AZ::Entity::State::Init) - { - m_gridEntity->Activate(); - } - else if (!enable && m_gridEntity->GetState() == AZ::Entity::State::Active) - { - m_gridEntity->Deactivate(); - } - } - } - - void MaterialViewportRenderer::OnAlternateSkyboxEnabledChanged(bool enable) - { - AZ_UNUSED(enable); - AZ::Render::LightingPresetPtr selectedPreset; - MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); - OnLightingPresetSelected(selectedPreset); - } - - void MaterialViewportRenderer::OnFieldOfViewChanged(float fieldOfView) - { - MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::SetFieldOfView, fieldOfView); - } - - void MaterialViewportRenderer::OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) - { - AZ::Render::DisplayMapperConfigurationDescriptor desc; - desc.m_operationType = operationType; - m_displayMapperFeatureProcessor->RegisterDisplayMapperConfiguration(desc); - } - - void MaterialViewportRenderer::OnAssetReady(AZ::Data::Asset asset) - { - if (m_modelAssetId == asset.GetId()) - { - MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::Reset); - AZ::Data::AssetBus::Handler::BusDisconnect(asset.GetId()); - } - } - - void MaterialViewportRenderer::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) - { - m_renderPipeline->AddToRenderTickOnce(); - - PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::GatherMetrics); - - if (m_shadowCatcherMaterial) - { - // Compile the m_shadowCatcherMaterial in OnTick because changes can only be compiled once per frame. - // This is ignored when a compile isn't needed. - m_shadowCatcherMaterial->Compile(); - } - } - - void MaterialViewportRenderer::OnTransformChanged(const AZ::Transform&, const AZ::Transform&) - { - const AZ::EntityId* currentBusId = AZ::TransformNotificationBus::GetCurrentBusId(); - if (m_cameraEntity && currentBusId && *currentBusId == m_cameraEntity->GetId() && m_directionalLightFeatureProcessor) - { - auto transform = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - transform, - m_cameraEntity->GetId(), - &AZ::TransformBus::Events::GetWorldTM); - for (const DirectionalLightHandle& id : m_lightHandles) - { - m_directionalLightFeatureProcessor->SetCameraTransform( - id, transform); - } - } - } -} diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h deleted file mode 100644 index 35b7965a2e..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace Render - { - class DisplayMapperFeatureProcessorInterface; - } - - class Entity; - class Component; - - namespace RPI - { - class SwapChainPass; - class WindowContext; - } -} - -namespace MaterialEditor -{ - //! Provides backend logic for MaterialViewport - //! Sets up a scene, camera, loads the model, and applies texture - class MaterialViewportRenderer - : public AZ::Data::AssetBus::Handler - , public AZ::TickBus::Handler - , public AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler - , public MaterialViewportNotificationBus::Handler - , public AZ::TransformNotificationBus::MultiHandler - { - public: - AZ_CLASS_ALLOCATOR(MaterialViewportRenderer, AZ::SystemAllocator, 0); - - MaterialViewportRenderer(AZStd::shared_ptr windowContext); - ~MaterialViewportRenderer(); - - AZStd::shared_ptr GetController(); - - private: - - // AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler interface overrides... - void OnDocumentOpened(const AZ::Uuid& documentId) override; - - // MaterialViewportNotificationBus::Handler interface overrides... - void OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset) override; - void OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) override; - void OnModelPresetSelected(AZ::Render::ModelPresetPtr preset) override; - void OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) override; - void OnShadowCatcherEnabledChanged(bool enable) override; - void OnGridEnabledChanged(bool enable) override; - void OnAlternateSkyboxEnabledChanged(bool enable) override; - void OnFieldOfViewChanged(float fieldOfView) override; - void OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) override; - - // AZ::Data::AssetBus::Handler interface overrides... - void OnAssetReady(AZ::Data::Asset asset) override; - - // AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - // AZ::TransformNotificationBus::MultiHandler overrides... - void OnTransformChanged(const AZ::Transform&, const AZ::Transform&) override; - - using DirectionalLightHandle = AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle; - - AZ::Data::Instance m_swapChainPass; - AZStd::string m_defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset"; - AZStd::shared_ptr m_windowContext; - AZ::RPI::RenderPipelinePtr m_renderPipeline; - AZ::RPI::ScenePtr m_scene; - AZ::Render::DirectionalLightFeatureProcessorInterface* m_directionalLightFeatureProcessor = nullptr; - AZ::Render::DisplayMapperFeatureProcessorInterface* m_displayMapperFeatureProcessor = nullptr; - - AZ::Entity* m_cameraEntity = nullptr; - AZ::Component* m_cameraComponent = nullptr; - bool m_cameraNeedsFullReset = true; - - AZ::Entity* m_postProcessEntity = nullptr; - - AZ::Entity* m_modelEntity = nullptr; - AZ::Data::AssetId m_modelAssetId; - - AZ::Entity* m_gridEntity = nullptr; - - AZ::Entity* m_shadowCatcherEntity = nullptr; - AZ::Data::Instance m_shadowCatcherMaterial; - AZ::RPI::MaterialPropertyIndex m_shadowCatcherOpacityPropertyIndex; - - AZStd::vector m_lightHandles; - - AZ::Entity* m_iblEntity = nullptr; - AZ::Render::SkyBoxFeatureProcessorInterface* m_skyboxFeatureProcessor = nullptr; - - AZStd::shared_ptr m_viewportController; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp index 0322fa194e..dd157c59ac 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp @@ -6,29 +6,65 @@ * */ +#undef RC_INVOKED + +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include #include +#include +#include #include #include #include - -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include -#include "Viewport/ui_MaterialViewportWidget.h" AZ_POP_DISABLE_WARNING -#include - namespace MaterialEditor { + static constexpr float DepthNear = 0.01f; MaterialViewportWidget::MaterialViewportWidget(QWidget* parent) : AtomToolsFramework::RenderViewportWidget(parent) , m_ui(new Ui::MaterialViewportWidget) + , m_viewportController(AZStd::make_shared()) { m_ui->setupUi(this); @@ -38,7 +74,415 @@ namespace MaterialEditor const AZ::Name defaultContextName = viewportContextManager->GetDefaultViewportContextName(); viewportContextManager->RenameViewportContext(GetViewportContext(), defaultContextName); - m_renderer = AZStd::make_unique(GetViewportContext()->GetWindowContext()); - GetControllerList()->Add(m_renderer->GetController()); + // Create and register a scene with all available feature processors + AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("MaterialViewport"); + m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); + m_scene->EnableAllFeatureProcessors(); + + // Bind m_defaultScene to the GameEntityContext's AzFramework::Scene + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "MaterialViewportWidget was unable to get the scene system during construction."); + AZStd::shared_ptr mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName); + + // This should never happen unless scene creation has changed. + AZ_Assert(mainScene, "Main scenes missing during system component initialization"); + mainScene->SetSubsystem(m_scene); + + // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene + AZ::Data::Asset pipelineAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath( + m_defaultPipelineAssetPath.c_str(), AZ::RPI::AssetUtils::TraceLevel::Error); + m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineAsset, *GetViewportContext()->GetWindowContext().get()); + pipelineAsset.Release(); + m_scene->AddRenderPipeline(m_renderPipeline); + + // As part of our initialization we need to create the BRDF texture generation pipeline + AZ::RPI::RenderPipelineDescriptor pipelineDesc; + pipelineDesc.m_mainViewTagName = "MainCamera"; + pipelineDesc.m_name = "BRDFTexturePipeline"; + pipelineDesc.m_rootPassTemplate = "BRDFTexturePipeline"; + pipelineDesc.m_executeOnce = true; + + AZ::RPI::RenderPipelinePtr brdfTexturePipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); + m_scene->AddRenderPipeline(brdfTexturePipeline); + + // Currently the scene has to be activated after render pipeline was added so some feature processors (i.e. imgui) can be + // initialized properly with pipeline's pass information. + m_scene->Activate(); + + AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); + + AzFramework::EntityContextId entityContextId; + AzFramework::GameEntityContextRequestBus::BroadcastResult( + entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId); + + // Configure camera + AzFramework::EntityContextRequestBus::EventResult( + m_cameraEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "Cameraentity"); + AZ_Assert(m_cameraEntity != nullptr, "Failed to create camera entity."); + + // Add debug camera and controller components + AZ::Debug::CameraComponentConfig cameraConfig(GetViewportContext()->GetWindowContext()); + cameraConfig.m_fovY = AZ::Constants::HalfPi; + cameraConfig.m_depthNear = DepthNear; + m_cameraComponent = m_cameraEntity->CreateComponent(azrtti_typeid()); + m_cameraComponent->SetConfiguration(cameraConfig); + m_cameraEntity->CreateComponent(azrtti_typeid()); + m_cameraEntity->Activate(); + + // Connect camera to pipeline's default view after camera entity activated + m_renderPipeline->SetDefaultViewFromEntity(m_cameraEntity->GetId()); + + // Configure tone mapper + AzFramework::EntityContextRequestBus::EventResult( + m_postProcessEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "postProcessEntity"); + AZ_Assert(m_postProcessEntity != nullptr, "Failed to create post process entity."); + + m_postProcessEntity->CreateComponent(AZ::Render::PostFxLayerComponentTypeId); + m_postProcessEntity->CreateComponent(AZ::Render::ExposureControlComponentTypeId); + m_postProcessEntity->CreateComponent(azrtti_typeid()); + m_postProcessEntity->Activate(); + + // Init directional light processor + m_directionalLightFeatureProcessor = m_scene->GetFeatureProcessor(); + + // Init display mapper processor + m_displayMapperFeatureProcessor = m_scene->GetFeatureProcessor(); + + // Init Skybox + m_skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); + m_skyboxFeatureProcessor->Enable(true); + m_skyboxFeatureProcessor->SetSkyboxMode(AZ::Render::SkyBoxMode::Cubemap); + + // Create IBL + AzFramework::EntityContextRequestBus::EventResult( + m_iblEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "IblEntity"); + AZ_Assert(m_iblEntity != nullptr, "Failed to create ibl entity."); + + m_iblEntity->CreateComponent(AZ::Render::ImageBasedLightComponentTypeId); + m_iblEntity->CreateComponent(azrtti_typeid()); + m_iblEntity->Activate(); + + // Create model + AzFramework::EntityContextRequestBus::EventResult( + m_modelEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); + AZ_Assert(m_modelEntity != nullptr, "Failed to create model entity."); + + m_modelEntity->CreateComponent(AZ::Render::MeshComponentTypeId); + m_modelEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); + m_modelEntity->CreateComponent(azrtti_typeid()); + m_modelEntity->Activate(); + + // Create shadow catcher + AzFramework::EntityContextRequestBus::EventResult( + m_shadowCatcherEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportShadowCatcher"); + AZ_Assert(m_shadowCatcherEntity != nullptr, "Failed to create shadow catcher entity."); + m_shadowCatcherEntity->CreateComponent(AZ::Render::MeshComponentTypeId); + m_shadowCatcherEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); + m_shadowCatcherEntity->CreateComponent(azrtti_typeid()); + m_shadowCatcherEntity->CreateComponent(azrtti_typeid()); + m_shadowCatcherEntity->Activate(); + + AZ::NonUniformScaleRequestBus::Event( + m_shadowCatcherEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, AZ::Vector3{ 100, 100, 1.0 }); + + AZ::Data::AssetId shadowCatcherModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath( + "materialeditor/viewportmodels/plane_1x1.azmodel", AZ::RPI::AssetUtils::TraceLevel::Error); + AZ::Render::MeshComponentRequestBus::Event( + m_shadowCatcherEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAssetId, shadowCatcherModelAssetId); + + auto shadowCatcherMaterialAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath( + "materials/special/shadowcatcher.azmaterial", AZ::RPI::AssetUtils::TraceLevel::Error); + if (shadowCatcherMaterialAsset) + { + m_shadowCatcherOpacityPropertyIndex = + shadowCatcherMaterialAsset->GetMaterialTypeAsset()->GetMaterialPropertiesLayout()->FindPropertyIndex( + AZ::Name{ "settings.opacity" }); + AZ_Error("MaterialViewportWidget", m_shadowCatcherOpacityPropertyIndex.IsValid(), "Could not find opacity property"); + + m_shadowCatcherMaterial = AZ::RPI::Material::Create(shadowCatcherMaterialAsset); + AZ_Error("MaterialViewportWidget", m_shadowCatcherMaterial != nullptr, "Could not create shadow catcher material."); + + AZ::Render::MaterialAssignmentMap shadowCatcherMaterials; + auto& shadowCatcherMaterialAssignment = shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId]; + shadowCatcherMaterialAssignment.m_materialInstance = m_shadowCatcherMaterial; + shadowCatcherMaterialAssignment.m_materialInstancePreCreated = true; + + AZ::Render::MaterialComponentRequestBus::Event( + m_shadowCatcherEntity->GetId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, + shadowCatcherMaterials); + } + + // Create grid + AzFramework::EntityContextRequestBus::EventResult( + m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid"); + AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity."); + + AZ::Render::GridComponentConfig gridConfig; + gridConfig.m_gridSize = 4.0f; + gridConfig.m_axisColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); + gridConfig.m_primaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); + gridConfig.m_secondaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); + auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId); + gridComponent->SetConfiguration(gridConfig); + + m_gridEntity->CreateComponent(azrtti_typeid()); + m_gridEntity->Activate(); + + OnDocumentOpened(AZ::Uuid::CreateNull()); + + // Attempt to apply the default lighting preset + AZ::Render::LightingPresetPtr lightingPreset; + MaterialViewportRequestBus::BroadcastResult(lightingPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + OnLightingPresetSelected(lightingPreset); + + // Attempt to apply the default model preset + AZ::Render::ModelPresetPtr modelPreset; + MaterialViewportRequestBus::BroadcastResult(modelPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); + OnModelPresetSelected(modelPreset); + + m_viewportController->Init(m_cameraEntity->GetId(), m_modelEntity->GetId(), m_iblEntity->GetId()); + + // Apply user settinngs restored since last run + AZStd::intrusive_ptr viewportSettings = + AZ::UserSettings::CreateFind(AZ::Crc32("MaterialViewportSettings"), AZ::UserSettings::CT_GLOBAL); + + OnGridEnabledChanged(viewportSettings->m_enableGrid); + OnShadowCatcherEnabledChanged(viewportSettings->m_enableShadowCatcher); + OnAlternateSkyboxEnabledChanged(viewportSettings->m_enableAlternateSkybox); + OnFieldOfViewChanged(viewportSettings->m_fieldOfView); + OnDisplayMapperOperationTypeChanged(viewportSettings->m_displayMapperOperationType); + + AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); + MaterialViewportNotificationBus::Handler::BusConnect(); + AZ::TickBus::Handler::BusConnect(); + AZ::TransformNotificationBus::MultiHandler::BusConnect(m_cameraEntity->GetId()); + + GetControllerList()->Add(m_viewportController); + } + + MaterialViewportWidget::~MaterialViewportWidget() + { + AZ::TransformNotificationBus::MultiHandler::BusDisconnect(); + AZ::TickBus::Handler::BusDisconnect(); + AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); + MaterialViewportNotificationBus::Handler::BusDisconnect(); + AZ::Data::AssetBus::Handler::BusDisconnect(); + + AzFramework::EntityContextId entityContextId; + AzFramework::GameEntityContextRequestBus::BroadcastResult( + entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId); + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_iblEntity); + m_iblEntity = nullptr; + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); + m_modelEntity = nullptr; + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_shadowCatcherEntity); + m_shadowCatcherEntity = nullptr; + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_gridEntity); + m_gridEntity = nullptr; + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_cameraEntity); + m_cameraEntity = nullptr; + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_postProcessEntity); + m_postProcessEntity = nullptr; + + for (DirectionalLightHandle& handle : m_lightHandles) + { + m_directionalLightFeatureProcessor->ReleaseLight(handle); + } + m_lightHandles.clear(); + + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "MaterialViewportWidget was unable to get the scene system during destruction."); + AZStd::shared_ptr mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName); + // This should never happen unless scene creation has changed. + AZ_Assert(mainScene, "Main scenes missing during system component destruction"); + mainScene->UnsetSubsystem(m_scene); + + m_swapChainPass = nullptr; + AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); + m_scene = nullptr; + } + + void MaterialViewportWidget::OnDocumentOpened(const AZ::Uuid& documentId) + { + AZ::Data::Instance materialInstance; + MaterialDocumentRequestBus::EventResult(materialInstance, documentId, &MaterialDocumentRequestBus::Events::GetInstance); + + AZ::Render::MaterialAssignmentMap materials; + auto& materialAssignment = materials[AZ::Render::DefaultMaterialAssignmentId]; + materialAssignment.m_materialInstance = materialInstance; + materialAssignment.m_materialInstancePreCreated = true; + + AZ::Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, materials); + } + + void MaterialViewportWidget::OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset) + { + if (!preset) + { + return; + } + + AZ::Render::ImageBasedLightFeatureProcessorInterface* iblFeatureProcessor = + m_scene->GetFeatureProcessor(); + AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor = + m_scene->GetFeatureProcessor(); + + AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface = + postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId()) + ->GetOrCreateExposureControlSettingsInterface(); + + Camera::Configuration cameraConfig; + Camera::CameraRequestBus::EventResult( + cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); + + bool enableAlternateSkybox = false; + MaterialViewportRequestBus::BroadcastResult(enableAlternateSkybox, &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled); + + preset->ApplyLightingPreset( + iblFeatureProcessor, m_skyboxFeatureProcessor, exposureControlSettingInterface, m_directionalLightFeatureProcessor, + cameraConfig, m_lightHandles, m_shadowCatcherMaterial, m_shadowCatcherOpacityPropertyIndex, enableAlternateSkybox); + } + + void MaterialViewportWidget::OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) + { + AZ::Render::LightingPresetPtr selectedPreset; + MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + if (selectedPreset == preset) + { + OnLightingPresetSelected(preset); + } + } + + void MaterialViewportWidget::OnModelPresetSelected(AZ::Render::ModelPresetPtr preset) + { + if (!preset) + { + return; + } + + if (!preset->m_modelAsset.GetId().IsValid()) + { + AZ_Warning( + "MaterialViewportWidget", false, "Attempting to set invalid model for preset: '%s'\n.", preset->m_displayName.c_str()); + return; + } + + if (preset->m_modelAsset.GetId() == m_modelAssetId) + { + return; + } + + AZ::Render::MeshComponentRequestBus::Event( + m_modelEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, preset->m_modelAsset); + + m_modelAssetId = preset->m_modelAsset.GetId(); + + AZ::Data::AssetBus::Handler::BusDisconnect(); + AZ::Data::AssetBus::Handler::BusConnect(m_modelAssetId); + } + + void MaterialViewportWidget::OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) + { + AZ::Render::ModelPresetPtr selectedPreset; + MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); + if (selectedPreset == preset) + { + OnModelPresetSelected(preset); + } + } + + void MaterialViewportWidget::OnShadowCatcherEnabledChanged(bool enable) + { + AZ::Render::MeshComponentRequestBus::Event( + m_shadowCatcherEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetVisibility, enable); + } + + void MaterialViewportWidget::OnGridEnabledChanged(bool enable) + { + if (m_gridEntity) + { + if (enable && m_gridEntity->GetState() == AZ::Entity::State::Init) + { + m_gridEntity->Activate(); + } + else if (!enable && m_gridEntity->GetState() == AZ::Entity::State::Active) + { + m_gridEntity->Deactivate(); + } + } + } + + void MaterialViewportWidget::OnAlternateSkyboxEnabledChanged(bool enable) + { + AZ_UNUSED(enable); + AZ::Render::LightingPresetPtr selectedPreset; + MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + OnLightingPresetSelected(selectedPreset); + } + + void MaterialViewportWidget::OnFieldOfViewChanged(float fieldOfView) + { + MaterialEditorViewportInputControllerRequestBus::Broadcast( + &MaterialEditorViewportInputControllerRequestBus::Handler::SetFieldOfView, fieldOfView); + } + + void MaterialViewportWidget::OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) + { + AZ::Render::DisplayMapperConfigurationDescriptor desc; + desc.m_operationType = operationType; + m_displayMapperFeatureProcessor->RegisterDisplayMapperConfiguration(desc); + } + + void MaterialViewportWidget::OnAssetReady(AZ::Data::Asset asset) + { + if (m_modelAssetId == asset.GetId()) + { + MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::Reset); + AZ::Data::AssetBus::Handler::BusDisconnect(asset.GetId()); + } + } + + void MaterialViewportWidget::OnTick(float deltaTime, AZ::ScriptTimePoint time) + { + AtomToolsFramework::RenderViewportWidget::OnTick(deltaTime, time); + + m_renderPipeline->AddToRenderTickOnce(); + + PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::GatherMetrics); + + if (m_shadowCatcherMaterial) + { + // Compile the m_shadowCatcherMaterial in OnTick because changes can only be compiled once per frame. + // This is ignored when a compile isn't needed. + m_shadowCatcherMaterial->Compile(); + } + } + + void MaterialViewportWidget::OnTransformChanged(const AZ::Transform&, const AZ::Transform&) + { + const AZ::EntityId* currentBusId = AZ::TransformNotificationBus::GetCurrentBusId(); + if (m_cameraEntity && currentBusId && *currentBusId == m_cameraEntity->GetId() && m_directionalLightFeatureProcessor) + { + auto transform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(transform, m_cameraEntity->GetId(), &AZ::TransformBus::Events::GetWorldTM); + for (const DirectionalLightHandle& id : m_lightHandles) + { + m_directionalLightFeatureProcessor->SetCameraTransform(id, transform); + } + } } } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.h index 2a71dcc1df..8a660c6603 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.h @@ -5,42 +5,115 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #if !defined(Q_MOC_RUN) +#include +#include +#include +#include +#include +#include +#include #include +#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include AZ_POP_DISABLE_WARNING #endif -#include +namespace AZ +{ + namespace Render + { + class DisplayMapperFeatureProcessorInterface; + } + + class Entity; + class Component; + + namespace RPI + { + class SwapChainPass; + class WindowContext; + } // namespace RPI +} // namespace AZ namespace Ui { class MaterialViewportWidget; } -namespace AZ -{ - namespace RPI - { - class WindowContext; - } -} - namespace MaterialEditor { - class MaterialViewportRenderer; - class MaterialViewportWidget : public AtomToolsFramework::RenderViewportWidget + , public AZ::Data::AssetBus::Handler + , public AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler + , public MaterialViewportNotificationBus::Handler + , public AZ::TransformNotificationBus::MultiHandler { public: MaterialViewportWidget(QWidget* parent = nullptr); + ~MaterialViewportWidget(); + + private: + // AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler interface overrides... + void OnDocumentOpened(const AZ::Uuid& documentId) override; + + // MaterialViewportNotificationBus::Handler interface overrides... + void OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset) override; + void OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) override; + void OnModelPresetSelected(AZ::Render::ModelPresetPtr preset) override; + void OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) override; + void OnShadowCatcherEnabledChanged(bool enable) override; + void OnGridEnabledChanged(bool enable) override; + void OnAlternateSkyboxEnabledChanged(bool enable) override; + void OnFieldOfViewChanged(float fieldOfView) override; + void OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) override; + + // AZ::Data::AssetBus::Handler interface overrides... + void OnAssetReady(AZ::Data::Asset asset) override; + + // AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + // AZ::TransformNotificationBus::MultiHandler overrides... + void OnTransformChanged(const AZ::Transform&, const AZ::Transform&) override; + + using DirectionalLightHandle = AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle; + + AZ::Data::Instance m_swapChainPass; + AZStd::string m_defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset"; + AZ::RPI::RenderPipelinePtr m_renderPipeline; + AZ::RPI::ScenePtr m_scene; + AZ::Render::DirectionalLightFeatureProcessorInterface* m_directionalLightFeatureProcessor = {}; + AZ::Render::DisplayMapperFeatureProcessorInterface* m_displayMapperFeatureProcessor = {}; + + AZ::Entity* m_cameraEntity = {}; + AZ::Component* m_cameraComponent = {}; + + AZ::Entity* m_postProcessEntity = {}; + + AZ::Entity* m_modelEntity = {}; + AZ::Data::AssetId m_modelAssetId; + + AZ::Entity* m_gridEntity = {}; + + AZ::Entity* m_shadowCatcherEntity = {}; + AZ::Data::Instance m_shadowCatcherMaterial; + AZ::RPI::MaterialPropertyIndex m_shadowCatcherOpacityPropertyIndex; + + AZStd::vector m_lightHandles; + + AZ::Entity* m_iblEntity = {}; + AZ::Render::SkyBoxFeatureProcessorInterface* m_skyboxFeatureProcessor = {}; + + AZStd::shared_ptr m_viewportController; QScopedPointer m_ui; - AZStd::unique_ptr m_renderer; }; } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake index 9d1e2b22f8..f7a15d2bcc 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake +++ b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake @@ -49,8 +49,6 @@ set(FILES Source/Viewport/MaterialViewportWidget.cpp Source/Viewport/MaterialViewportWidget.h Source/Viewport/MaterialViewportWidget.ui - Source/Viewport/MaterialViewportRenderer.cpp - Source/Viewport/MaterialViewportRenderer.h Source/Viewport/PerformanceMonitorComponent.cpp Source/Viewport/PerformanceMonitorComponent.h From 0d2204917e1d6ac6a3e598df041890666bec5312 Mon Sep 17 00:00:00 2001 From: Scott Romero <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 24 Jan 2022 09:49:13 -0800 Subject: [PATCH 13/20] [development] enabled mouse wheel scrolling in the Profiler gem visualizer (#6930) Resolves #6698 Signed-off-by: AMZN-ScottR 24445312+AMZN-ScottR@users.noreply.github.com --- Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index 27397f05f7..3e071570bd 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -536,8 +536,7 @@ namespace Profiler ImGui::Columns(1, "TimelineColumn", true); // Timeline - if (ImGui::BeginChild( - "Timeline", { 0, 0 }, true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) + if (ImGui::BeginChild("Timeline", { 0, 0 }, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { // Find the next frame boundary after the viewport's right bound and draw until that tick auto nextFrameBoundaryItr = AZStd::lower_bound(m_frameEndTicks.begin(), m_frameEndTicks.end(), m_viewportEndTick); From 7bf7b03dd290af04e169ab6ea037e1f8b24d7962 Mon Sep 17 00:00:00 2001 From: SWMasterson Date: Mon, 24 Jan 2022 09:50:37 -0800 Subject: [PATCH 14/20] Added base level for tests, updated automation to use prefabs, and restored sandboxed tests (#6993) Signed-off-by: Sean Masterson --- .../Gem/PythonTests/Atom/TestSuite_Main.py | 10 +++- .../Gem/PythonTests/Atom/TestSuite_Sandbox.py | 10 ---- ...ntsLevel_DiffuseGlobalIlluminationAdded.py | 6 +-- ...ditorComponentsLevel_DisplayMapperAdded.py | 4 +- .../hydra_AtomEditorComponents_BloomAdded.py | 4 +- .../hydra_AtomEditorComponents_DecalAdded.py | 3 +- ...a_AtomEditorComponents_DeferredFogAdded.py | 4 +- ..._AtomEditorComponents_DepthOfFieldAdded.py | 4 +- ...mEditorComponents_DiffuseProbeGridAdded.py | 4 +- ...mEditorComponents_DirectionalLightAdded.py | 4 +- ...AtomEditorComponents_DisplayMapperAdded.py | 4 +- ...omEditorComponents_EntityReferenceAdded.py | 4 +- ...omEditorComponents_ExposureControlAdded.py | 4 +- ...EditorComponents_GlobalSkylightIBLAdded.py | 4 +- .../hydra_AtomEditorComponents_GridAdded.py | 4 +- ...omEditorComponents_HDRColorGradingAdded.py | 4 +- ...ra_AtomEditorComponents_HDRiSkyboxAdded.py | 4 +- .../hydra_AtomEditorComponents_LightAdded.py | 4 +- ...mEditorComponents_LookModificationAdded.py | 4 +- ...ydra_AtomEditorComponents_MaterialAdded.py | 4 +- .../hydra_AtomEditorComponents_MeshAdded.py | 4 +- ...orComponents_OcclusionCullingPlaneAdded.py | 4 +- ...a_AtomEditorComponents_PhysicalSkyAdded.py | 4 +- ...nents_PostFXGradientWeightModifierAdded.py | 4 +- ...a_AtomEditorComponents_PostFXLayerAdded.py | 4 +- ...ponents_PostFXRadiusWeightModifierAdded.py | 4 +- ...mponents_PostFxShapeWeightModifierAdded.py | 4 +- ...omEditorComponents_ReflectionProbeAdded.py | 4 +- .../hydra_AtomEditorComponents_SSAOAdded.py | 4 +- .../Graphics/base_empty/base_empty.prefab | 53 +++++++++++++++++++ .../Levels/Graphics/base_empty/tags.txt | 12 +++++ 31 files changed, 153 insertions(+), 41 deletions(-) create mode 100644 AutomatedTesting/Levels/Graphics/base_empty/base_empty.prefab create mode 100644 AutomatedTesting/Levels/Graphics/base_empty/tags.txt diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py index f1e66ac492..cca20bbf8c 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py @@ -21,7 +21,7 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") @pytest.mark.parametrize("launcher_platform", ['windows_editor']) class TestAutomation(EditorTestSuite): - enable_prefab_system = False + enable_prefab_system = True @pytest.mark.test_case_id("C36525657") class AtomEditorComponents_BloomAdded(EditorSharedTest): @@ -120,6 +120,14 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_SSAOAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_SSAOAdded as test_module + @pytest.mark.test_case_id("C36529666") + class AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded as test_module + + @pytest.mark.test_case_id("C36525660") + class AtomEditorComponentsLevel_DisplayMapperAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponentsLevel_DisplayMapperAdded as test_module + class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py index bd0477a1db..5299e55a2b 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py @@ -26,13 +26,3 @@ class TestAutomation(EditorTestSuite): @pytest.mark.test_case_id("C36525660") class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module - - # this test causes editor to crash when using slices. once automation transitions to prefabs it should pass - @pytest.mark.test_case_id("C36529666") - class AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded as test_module - - # this test causes editor to crash when using slices. once automation transitions to prefabs it should pass - @pytest.mark.test_case_id("C36525660") - class AtomEditorComponentsLevel_DisplayMapperAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponentsLevel_DisplayMapperAdded as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py index ddcd5c3c46..0c9b39e354 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py @@ -60,7 +60,7 @@ def AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Add Diffuse Global Illumination level component to the level entity. @@ -86,10 +86,10 @@ def AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity(): # 4. Set Quality Level property to Low diffuse_global_illumination_component.set_component_property_value( - AtomComponentProperties.diffuse_global_illumination('Quality Level', GLOBAL_ILLUMINATION_QUALITY['Low'])) + AtomComponentProperties.diffuse_global_illumination('Quality Level'), GLOBAL_ILLUMINATION_QUALITY['Low']) quality = diffuse_global_illumination_component.get_component_property_value( AtomComponentProperties.diffuse_global_illumination('Quality Level')) - Report.result(diffuse_global_illumination_quality, quality == GLOBAL_ILLUMINATION_QUALITY['Low']) + Report.result(Tests.diffuse_global_illumination_quality, quality == GLOBAL_ILLUMINATION_QUALITY['Low']) # 5. Enter/Exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py index c050dd76d4..f9660957bb 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py @@ -67,7 +67,7 @@ def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Add Display Mapper level component to the level entity. @@ -102,7 +102,7 @@ def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity(): display_mapper_component.set_component_property_value( AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True) Report.result( - Test.enable_ldr_color_grading_lut, + Tests.enable_ldr_color_grading_lut, display_mapper_component.get_component_property_value( AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py index 56b22eb20d..ce29a1de88 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py @@ -97,7 +97,7 @@ def AtomEditorComponents_Bloom_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an Bloom entity with no components. @@ -170,10 +170,12 @@ def AtomEditorComponents_Bloom_AddedToEntity(): # 13. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, bloom_entity.exists()) # 14. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not bloom_entity.exists()) # 15. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py index e840cf3cf1..eb5e24e3a6 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py @@ -95,7 +95,7 @@ def AtomEditorComponents_Decal_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Decal entity with no components. @@ -162,6 +162,7 @@ def AtomEditorComponents_Decal_AddedToEntity(): # 11. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not decal_entity.exists()) # 12. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DeferredFogAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DeferredFogAdded.py index 71163ece94..f1578cbf8d 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DeferredFogAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DeferredFogAdded.py @@ -97,7 +97,7 @@ def AtomEditorComponents_DeferredFog_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an Deferred Fog entity with no components. @@ -174,10 +174,12 @@ def AtomEditorComponents_DeferredFog_AddedToEntity(): # 13. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, deferred_fog_entity.exists()) # 14. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not deferred_fog_entity.exists()) # 15. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py index e2c5f9c77d..3913420981 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py @@ -107,7 +107,7 @@ def AtomEditorComponents_DepthOfField_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a DepthOfField entity with no components. @@ -189,10 +189,12 @@ def AtomEditorComponents_DepthOfField_AddedToEntity(): # 15. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, depth_of_field_entity.exists()) # 16. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not depth_of_field_entity.exists()) # 17. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DiffuseProbeGridAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DiffuseProbeGridAdded.py index f42c091057..04b4f7876b 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DiffuseProbeGridAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DiffuseProbeGridAdded.py @@ -90,7 +90,7 @@ def AtomEditorComponents_DiffuseProbeGrid_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Diffuse Probe Grid entity with no components. @@ -168,10 +168,12 @@ def AtomEditorComponents_DiffuseProbeGrid_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, diffuse_probe_grid_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not diffuse_probe_grid_entity.exists()) # 14. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py index f3ffc0f366..19cfbedcd5 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py @@ -95,7 +95,7 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Directional Light entity with no components. @@ -168,10 +168,12 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, directional_light_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not directional_light_entity.exists()) # 14. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py index 558d69046e..d3ea669eab 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py @@ -91,7 +91,7 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Display Mapper entity with no components. @@ -166,10 +166,12 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity(): # 11. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, display_mapper_entity.exists()) # 12. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not display_mapper_entity.exists()) # 13. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py index dddcca64fa..ec402f0f5f 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py @@ -81,7 +81,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an Entity Reference entity with no components. @@ -139,10 +139,12 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, entity_reference_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not entity_reference_entity.exists()) # 11. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py index 6fa9660539..f60f0e18be 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py @@ -101,7 +101,7 @@ def AtomEditorComponents_ExposureControl_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Creation of Exposure Control entity with no components. @@ -169,10 +169,12 @@ def AtomEditorComponents_ExposureControl_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, exposure_control_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not exposure_control_entity.exists()) # 14. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py index 7f0c38e289..0e8e6fa43e 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py @@ -99,7 +99,7 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Global Skylight (IBL) entity with no components. @@ -176,10 +176,12 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity(): # 11. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, global_skylight_entity.exists()) # 12. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not global_skylight_entity.exists()) # 13. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py index a77a1f50a4..3c6d261f22 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py @@ -82,7 +82,7 @@ def AtomEditorComponents_Grid_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Grid entity with no components. @@ -139,10 +139,12 @@ def AtomEditorComponents_Grid_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, grid_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not grid_entity.exists()) # 11. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py index 4972079fcd..5846206e50 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py @@ -96,7 +96,7 @@ def AtomEditorComponents_HDRColorGrading_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an HDR Color Grading entity with no components. @@ -173,10 +173,12 @@ def AtomEditorComponents_HDRColorGrading_AddedToEntity(): # 13. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, hdr_color_grading_entity.exists()) # 14. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not hdr_color_grading_entity.exists()) # 15. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRiSkyboxAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRiSkyboxAdded.py index 0f96bc5424..fc093b60db 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRiSkyboxAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRiSkyboxAdded.py @@ -87,7 +87,7 @@ def AtomEditorComponents_HDRiSkybox_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an HDRi Skybox with no components. @@ -158,10 +158,12 @@ def AtomEditorComponents_HDRiSkybox_AddedToEntity(): # 10. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, hdri_skybox_entity.exists()) # 11. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not hdri_skybox_entity.exists()) # 12. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py index 249671556d..75a04612a3 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py @@ -89,7 +89,7 @@ def AtomEditorComponents_Light_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Light entity with no components. @@ -144,10 +144,12 @@ def AtomEditorComponents_Light_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, light_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not light_entity.exists()) # 11. Look for errors asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LookModificationAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LookModificationAdded.py index afb8033426..149af73151 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LookModificationAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LookModificationAdded.py @@ -104,7 +104,7 @@ def AtomEditorComponents_LookModification_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an Look Modification entity with no components. @@ -192,10 +192,12 @@ def AtomEditorComponents_LookModification_AddedToEntity(): # 14. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, look_modification_entity.exists()) # 15. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not look_modification_entity.exists()) # 16. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py index c613bb23e7..919a6753f4 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py @@ -102,7 +102,7 @@ def AtomEditorComponents_Material_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Material entity with no components. @@ -184,10 +184,12 @@ def AtomEditorComponents_Material_AddedToEntity(): # 16. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, material_entity.exists()) # 17. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not material_entity.exists()) # 18. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py index 9d56753961..a87ee75b53 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py @@ -87,7 +87,7 @@ def AtomEditorComponents_Mesh_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Mesh entity with no components. @@ -151,10 +151,12 @@ def AtomEditorComponents_Mesh_AddedToEntity(): # 10. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, mesh_entity.exists()) # 11. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not mesh_entity.exists()) # 12. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py index 4226ae3dfe..56bb5eb68c 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py @@ -80,7 +80,7 @@ def AtomEditorComponents_OcclusionCullingPlane_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a occlusion culling plane entity with no components. @@ -140,10 +140,12 @@ def AtomEditorComponents_OcclusionCullingPlane_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, occlusion_culling_plane_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not occlusion_culling_plane_entity.exists()) # 11. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py index fa8c626016..e0c558811e 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py @@ -89,7 +89,7 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Physical Sky entity with no components. @@ -146,10 +146,12 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, physical_sky_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not physical_sky_entity.exists()) # 11. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py index 6e4ae2d9ac..b36267433f 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py @@ -92,7 +92,7 @@ def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a PostFX Gradient Weight Modifier entity with no components. @@ -162,10 +162,12 @@ def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, postfx_gradient_weight_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not postfx_gradient_weight_entity.exists()) # 14. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py index efef4c0a43..07fffb9bde 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py @@ -80,7 +80,7 @@ def AtomEditorComponents_postfx_layer_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a PostFX Layer entity with no components. @@ -137,10 +137,12 @@ def AtomEditorComponents_postfx_layer_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, postfx_layer_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not postfx_layer_entity.exists()) # 11. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py index 228ddfcdc5..616233d2d2 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py @@ -92,7 +92,7 @@ def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Post FX Radius Weight Modifier entity with no components. @@ -161,10 +161,12 @@ def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, postfx_radius_weight_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not postfx_radius_weight_entity.exists()) # 14. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py index 0a37ac6bf7..5f7d571a18 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py @@ -98,7 +98,7 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a PostFx Shape Weight Modifier entity with no components. @@ -188,10 +188,12 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): # 15. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, postfx_shape_weight_entity.exists()) # 16. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not postfx_shape_weight_entity.exists()) # 17. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py index 70adf9143a..85156b4db6 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py @@ -97,7 +97,7 @@ def AtomEditorComponents_ReflectionProbe_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Reflection Probe entity with no components. @@ -183,10 +183,12 @@ def AtomEditorComponents_ReflectionProbe_AddedToEntity(): # 13. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, reflection_probe_entity.exists()) # 14. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not reflection_probe_entity.exists()) # 15. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_SSAOAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_SSAOAdded.py index 15f40f8b70..09f77c4a9f 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_SSAOAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_SSAOAdded.py @@ -94,7 +94,7 @@ def AtomEditorComponents_SSAO_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a SSAO entity with no components. @@ -163,10 +163,12 @@ def AtomEditorComponents_SSAO_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, ssao_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not ssao_entity.exists()) # 14. Look for errors and asserts. diff --git a/AutomatedTesting/Levels/Graphics/base_empty/base_empty.prefab b/AutomatedTesting/Levels/Graphics/base_empty/base_empty.prefab new file mode 100644 index 0000000000..f7e42e7731 --- /dev/null +++ b/AutomatedTesting/Levels/Graphics/base_empty/base_empty.prefab @@ -0,0 +1,53 @@ +{ + "ContainerEntity": { + "Id": "Entity_[1146574390643]", + "Name": "Level", + "Components": { + "Component_[10641544592923449938]": { + "$type": "EditorInspectorComponent", + "Id": 10641544592923449938 + }, + "Component_[12039882709170782873]": { + "$type": "EditorOnlyEntityComponent", + "Id": 12039882709170782873 + }, + "Component_[12265484671603697631]": { + "$type": "EditorPendingCompositionComponent", + "Id": 12265484671603697631 + }, + "Component_[14126657869720434043]": { + "$type": "EditorEntitySortComponent", + "Id": 14126657869720434043 + }, + "Component_[15230859088967841193]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 15230859088967841193, + "Parent Entity": "" + }, + "Component_[16239496886950819870]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 16239496886950819870 + }, + "Component_[5688118765544765547]": { + "$type": "EditorEntityIconComponent", + "Id": 5688118765544765547 + }, + "Component_[6545738857812235305]": { + "$type": "SelectionComponent", + "Id": 6545738857812235305 + }, + "Component_[7247035804068349658]": { + "$type": "EditorPrefabComponent", + "Id": 7247035804068349658 + }, + "Component_[9307224322037797205]": { + "$type": "EditorLockComponent", + "Id": 9307224322037797205 + }, + "Component_[9562516168917670048]": { + "$type": "EditorVisibilityComponent", + "Id": 9562516168917670048 + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Graphics/base_empty/tags.txt b/AutomatedTesting/Levels/Graphics/base_empty/tags.txt new file mode 100644 index 0000000000..0d6c1880e7 --- /dev/null +++ b/AutomatedTesting/Levels/Graphics/base_empty/tags.txt @@ -0,0 +1,12 @@ +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 From 2b7b975a88ecd90a59376d94aae3c0ad37020ac2 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 24 Jan 2022 12:38:29 -0600 Subject: [PATCH 15/20] Fixed missing include compile issue Signed-off-by: Chris Galvan --- Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp b/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp index cf042dc4ac..0640271c37 100644 --- a/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include From 1cf7d57b3fffa89367218cc3a82cc6172e4fdd8a Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:20:15 -0800 Subject: [PATCH 16/20] Update deployment scripts to support AWSI automation tests on Linux (#7038) * Update deployment scripts to support AWSI automation tests on Linux Signed-off-by: Junbo Liang <68558268+junbo75@users.noreply.github.com> --- .../Gem/PythonTests/AWS/CMakeLists.txt | 6 ------ AutomatedTesting/Gem/PythonTests/AWS/README.md | 2 +- .../PythonTests/AWS/common/aws_credentials.py | 4 ++++ .../Gem/PythonTests/AWS/common/aws_utils.py | 2 +- .../Gem/PythonTests/AWS/common/constants.py | 4 +++- scripts/build/Platform/Linux/build_config.json | 4 ++-- .../Platform/Linux/deploy_cdk_applications.sh | 17 ++++++++++------- .../Platform/Linux/destroy_cdk_applications.sh | 16 ++++++++++------ scripts/build/Platform/Linux/pipeline.json | 14 -------------- .../Windows/deploy_cdk_applications.cmd | 4 ++++ .../Windows/destroy_cdk_applications.cmd | 3 +++ scripts/build/Platform/Windows/pipeline.json | 14 -------------- 12 files changed, 38 insertions(+), 52 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/AWS/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/AWS/CMakeLists.txt index c8629bbe8b..10e90ecbfc 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/AWS/CMakeLists.txt @@ -12,12 +12,6 @@ ################################################################################ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) - # Only enable AWS automated tests on Windows - set(SUPPORTED_PLATFORMS "Windows" "Linux") - if (NOT "${PAL_PLATFORM_NAME}" IN_LIST SUPPORTED_PLATFORMS) - return() - endif() - ly_add_pytest( NAME AutomatedTesting::AWSTests TEST_SUITE awsi diff --git a/AutomatedTesting/Gem/PythonTests/AWS/README.md b/AutomatedTesting/Gem/PythonTests/AWS/README.md index a25f39d9c2..73ef685261 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/README.md +++ b/AutomatedTesting/Gem/PythonTests/AWS/README.md @@ -3,7 +3,7 @@ ## Prerequisites 1. Build the O3DE Editor and AutomatedTesting.GameLauncher in Profile. 2. Install the latest version of NodeJs. -3. AWS CLI is installed and configured following [Configuration and Credential File Settings](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html). +3. AWS CLI is installed and AWS crendentials are configured via [environment variables](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html) or [default profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html). 4. [AWS Cloud Development Kit (CDK)](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#getting_started_install) is installed. ## Deploy CDK Applications diff --git a/AutomatedTesting/Gem/PythonTests/AWS/common/aws_credentials.py b/AutomatedTesting/Gem/PythonTests/AWS/common/aws_credentials.py index c6401f2828..d0bbfe7c3e 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/common/aws_credentials.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/common/aws_credentials.py @@ -68,6 +68,10 @@ class AwsCredentials: if (len(self._credentials.sections()) == 0) and (not self._credentials_file_exists): os.remove(self._credentials_path) return + + credentials_file_dir = os.path.dirname(self._credentials_path) + if not os.path.isdir(credentials_file_dir): + os.makedirs(credentials_file_dir) with open(self._credentials_path, 'w+') as credential_file: self._credentials.write(credential_file) diff --git a/AutomatedTesting/Gem/PythonTests/AWS/common/aws_utils.py b/AutomatedTesting/Gem/PythonTests/AWS/common/aws_utils.py index 92f3762e71..2a5efbd03f 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/common/aws_utils.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/common/aws_utils.py @@ -16,7 +16,7 @@ logging.getLogger('nose').setLevel(logging.WARNING) class AwsUtils: def __init__(self, arn: str, session_name: str, region_name: str): - local_session = boto3.Session(profile_name='default') + local_session = boto3.Session() local_sts_client = local_session.client('sts') self._local_account_id = local_sts_client.get_caller_identity()["Account"] logger.info(f'Local Account Id: {self._local_account_id}') diff --git a/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py b/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py index b12aca5f29..a38974073a 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py @@ -6,11 +6,13 @@ SPDX-License-Identifier: Apache-2.0 OR MIT """ import os +import platform # ARN of the IAM role to assume for retrieving temporary AWS credentials ASSUME_ROLE_ARN = os.environ.get('ASSUME_ROLE_ARN', 'arn:aws:iam::645075835648:role/o3de-automation-tests') # Name of the AWS project deployed by the CDK applications -AWS_PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME', 'AWSAUTO') +AWS_PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME').upper() if os.environ.get('O3DE_AWS_PROJECT_NAME') else \ + (os.environ.get('BRANCH_NAME', '') + '-' + os.environ.get('PIPELINE_NAME', '') + '-' + platform.system()).upper() # Region for the existing CloudFormation stacks used by the automation tests AWS_REGION = os.environ.get('O3DE_AWS_DEPLOY_REGION', 'us-east-1') # Name of the default resource mapping config file used by the automation tests diff --git a/scripts/build/Platform/Linux/build_config.json b/scripts/build/Platform/Linux/build_config.json index f61f91169a..c8f8752609 100644 --- a/scripts/build/Platform/Linux/build_config.json +++ b/scripts/build/Platform/Linux/build_config.json @@ -185,11 +185,11 @@ "COMMAND": "build_test_linux.sh", "PARAMETERS": { "CONFIGURATION": "profile", - "OUTPUT_DIRECTORY": "build\\linux", + "OUTPUT_DIRECTORY": "build/linux", "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_awsi", - "CTEST_OPTIONS": "-L \"(SUITE_awsi)\" --no-tests=error", + "CTEST_OPTIONS": "-L (SUITE_awsi) --no-tests=error", "TEST_RESULTS": "True" } }, diff --git a/scripts/build/Platform/Linux/deploy_cdk_applications.sh b/scripts/build/Platform/Linux/deploy_cdk_applications.sh index 9a0a31397e..cccc796bdb 100755 --- a/scripts/build/Platform/Linux/deploy_cdk_applications.sh +++ b/scripts/build/Platform/Linux/deploy_cdk_applications.sh @@ -1,5 +1,5 @@ -#!/bin/bash - +#!/usr/bin/env bash +# # Copyright (c) Contributors to the Open 3D Engine Project. # For complete copyright and license terms please see the LICENSE at the root of this distribution. # @@ -8,7 +8,7 @@ # Deploy the CDK applications for AWS gems (Linux only) -SOURCE_DIRECTORY=$(dirname "$0") +SOURCE_DIRECTORY=$PWD PATH=$SOURCE_DIRECTORY/python:$PATH GEM_DIRECTORY=$SOURCE_DIRECTORY/Gems @@ -80,11 +80,14 @@ fi # Set temporary AWS credentials from the assume role credentials=$(aws sts assume-role --query Credentials.[SecretAccessKey,SessionToken,AccessKeyId] --output text --role-arn $ASSUME_ROLE_ARN --role-session-name o3de-Automation-session) -AWS_SECRET_ACCESS_KEY=$(echo "$credentials" | cut -d' ' -f1) -AWS_SESSION_TOKEN=$(echo "$credentials" | cut -d' ' -f2) -AWS_ACCESS_KEY_ID=$(echo "$credentials" | cut -d' ' -f3) +export AWS_SECRET_ACCESS_KEY=$(echo $credentials | cut -d' ' -f1) +export AWS_SESSION_TOKEN=$(echo $credentials | cut -d' ' -f2) +export AWS_ACCESS_KEY_ID=$(echo $credentials | cut -d' ' -f3) -O3DE_AWS_DEPLOY_ACCOUNT=$(echo "$ASSUME_ROLE_ARN" | cut -d':' -f5) +export O3DE_AWS_DEPLOY_ACCOUNT=$(echo "$ASSUME_ROLE_ARN" | cut -d':' -f5) +if [[ -z "$O3DE_AWS_PROJECT_NAME" ]]; then + export O3DE_AWS_PROJECT_NAME=$BRANCH_NAME-$PIPELINE_NAME-Linux +fi # Bootstrap and deploy the CDK applications echo [cdk_bootstrap] Bootstrap CDK diff --git a/scripts/build/Platform/Linux/destroy_cdk_applications.sh b/scripts/build/Platform/Linux/destroy_cdk_applications.sh index 54f84911a6..fd91e1a786 100755 --- a/scripts/build/Platform/Linux/destroy_cdk_applications.sh +++ b/scripts/build/Platform/Linux/destroy_cdk_applications.sh @@ -11,7 +11,7 @@ # 1) Node.js is installed # 2) Node.js version >= 10.13.0, except for versions 13.0.0 - 13.6.0. A version in active long-term support is recommended. -SOURCE_DIRECTORY=$(dirname "$0") +SOURCE_DIRECTORY=$PWD PATH=$SOURCE_DIRECTORY/python:$PATH GEM_DIRECTORY=$SOURCE_DIRECTORY/Gems @@ -70,12 +70,12 @@ echo [cdk_installation] Install the current version of nodejs nvm install node echo [cdk_installation] Install the latest version of CDK -if ! sudo npm uninstall -g aws-cdk; +if ! npm uninstall -g aws-cdk; then echo [cdk_bootstrap] Failed to uninstall the current version of CDK exit 1 fi -if ! sudo npm install -g aws-cdk@latest; +if ! npm install -g aws-cdk@latest; then echo [cdk_bootstrap] Failed to install the latest version of CDK exit 1 @@ -83,9 +83,13 @@ fi # Set temporary AWS credentials from the assume role credentials=$(aws sts assume-role --query Credentials.[SecretAccessKey,SessionToken,AccessKeyId] --output text --role-arn $ASSUME_ROLE_ARN --role-session-name o3de-Automation-session) -AWS_SECRET_ACCESS_KEY=$(echo "$credentials" | cut -d' ' -f1) -AWS_SESSION_TOKEN=$(echo "$credentials" | cut -d' ' -f2) -AWS_ACCESS_KEY_ID=$(echo "$credentials" | cut -d' ' -f3) +export AWS_SECRET_ACCESS_KEY=$(echo $credentials | cut -d' ' -f1) +export AWS_SESSION_TOKEN=$(echo $credentials | cut -d' ' -f2) +export AWS_ACCESS_KEY_ID=$(echo $credentials | cut -d' ' -f3) + +if [[ -z "$O3DE_AWS_PROJECT_NAME" ]]; then + export O3DE_AWS_PROJECT_NAME=$BRANCH_NAME-$PIPELINE_NAME-Linux +fi ERROR_EXISTS=0 DestroyCDKApplication AWSCore diff --git a/scripts/build/Platform/Linux/pipeline.json b/scripts/build/Platform/Linux/pipeline.json index e9667d312d..605adf1837 100644 --- a/scripts/build/Platform/Linux/pipeline.json +++ b/scripts/build/Platform/Linux/pipeline.json @@ -16,13 +16,6 @@ }, "PIPELINE_JENKINS_PARAMETERS": { "nightly-incremental": [ - { - "parameter_name": "O3DE_AWS_PROJECT_NAME", - "parameter_type": "string", - "default_value": "", - "use_last_run_value": true, - "description": "The name of the O3DE project that stacks should be deployed for." - }, { "parameter_name": "O3DE_AWS_DEPLOY_REGION", "parameter_type": "string", @@ -46,13 +39,6 @@ } ], "nightly-clean": [ - { - "parameter_name": "O3DE_AWS_PROJECT_NAME", - "parameter_type": "string", - "default_value": "", - "use_last_run_value": true, - "description": "The name of the O3DE project that stacks should be deployed for." - }, { "parameter_name": "O3DE_AWS_DEPLOY_REGION", "parameter_type": "string", diff --git a/scripts/build/Platform/Windows/deploy_cdk_applications.cmd b/scripts/build/Platform/Windows/deploy_cdk_applications.cmd index f3d68d2fe8..fca0835bd8 100644 --- a/scripts/build/Platform/Windows/deploy_cdk_applications.cmd +++ b/scripts/build/Platform/Windows/deploy_cdk_applications.cmd @@ -49,6 +49,10 @@ FOR /f "tokens=1,2,3" %%a IN ('CALL aws sts assume-role --query Credentials.[Sec ) FOR /F "tokens=4 delims=:" %%a IN ("%ASSUME_ROLE_ARN%") DO SET O3DE_AWS_DEPLOY_ACCOUNT=%%a +IF "%O3DE_AWS_PROJECT_NAME%"=="" ( + SET O3DE_AWS_PROJECT_NAME=%BRANCH_NAME%-%PIPELINE_NAME%-Windows +) + REM Bootstrap and deploy the CDK applications ECHO [cdk_bootstrap] Bootstrap CDK CALL cdk bootstrap aws://%O3DE_AWS_DEPLOY_ACCOUNT%/%O3DE_AWS_DEPLOY_REGION% diff --git a/scripts/build/Platform/Windows/destroy_cdk_applications.cmd b/scripts/build/Platform/Windows/destroy_cdk_applications.cmd index dacc9d327a..fe57619ff9 100644 --- a/scripts/build/Platform/Windows/destroy_cdk_applications.cmd +++ b/scripts/build/Platform/Windows/destroy_cdk_applications.cmd @@ -48,6 +48,9 @@ FOR /f "tokens=1,2,3" %%a IN ('CALL aws sts assume-role --query Credentials.[Sec SET AWS_ACCESS_KEY_ID=%%c ) FOR /F "tokens=4 delims=:" %%a IN ("%ASSUME_ROLE_ARN%") DO SET O3DE_AWS_DEPLOY_ACCOUNT=%%a +IF "%O3DE_AWS_PROJECT_NAME%"=="" ( + SET O3DE_AWS_PROJECT_NAME=%BRANCH_NAME%-%PIPELINE_NAME%-Windows +) SET ERROR_EXISTS=0 CALL :DestroyCDKApplication AWSCore,ERROR_EXISTS diff --git a/scripts/build/Platform/Windows/pipeline.json b/scripts/build/Platform/Windows/pipeline.json index 28d8437408..47e6af2d10 100644 --- a/scripts/build/Platform/Windows/pipeline.json +++ b/scripts/build/Platform/Windows/pipeline.json @@ -16,13 +16,6 @@ }, "PIPELINE_JENKINS_PARAMETERS": { "nightly-incremental": [ - { - "parameter_name": "O3DE_AWS_PROJECT_NAME", - "parameter_type": "string", - "default_value": "", - "use_last_run_value": true, - "description": "The name of the O3DE project that stacks should be deployed for." - }, { "parameter_name": "O3DE_AWS_DEPLOY_REGION", "parameter_type": "string", @@ -46,13 +39,6 @@ } ], "nightly-clean": [ - { - "parameter_name": "O3DE_AWS_PROJECT_NAME", - "parameter_type": "string", - "default_value": "", - "use_last_run_value": true, - "description": "The name of the O3DE project that stacks should be deployed for." - }, { "parameter_name": "O3DE_AWS_DEPLOY_REGION", "parameter_type": "string", From b1caed0f8ea5cf8ed14b6daf0d65c1cf7eea2dae Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:22:50 -0800 Subject: [PATCH 17/20] Introduce shortcut labeling in "Find in Viewport" context menu item in the Outliner (#7095) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index c499d0f92f..31bb067603 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -890,6 +890,7 @@ namespace AzToolsFramework m_actionGoToEntitiesInViewport = new QAction(tr("Find in viewport"), this); m_actionGoToEntitiesInViewport->setShortcutContext(Qt::WidgetWithChildrenShortcut); + m_actionGoToEntitiesInViewport->setShortcut(tr("Z")); connect(m_actionGoToEntitiesInViewport, &QAction::triggered, this, &EntityOutlinerWidget::GoToEntitiesInViewport); addAction(m_actionGoToEntitiesInViewport); } From f34d3a822e06ac1a12b42a18cb5b18afa15eabf2 Mon Sep 17 00:00:00 2001 From: bosnichd Date: Mon, 24 Jan 2022 13:47:44 -0700 Subject: [PATCH 18/20] Add a ray cast API to the terrain system, implement it, and use it so entities can be placed on top of terrain. (#6895) * Add a ray cast API to the terrain system, implement it, and use it so entities can be placed on top of terrain. Still to do: - Unit tests - Profiling/benchmarks - Optimization (if needed, may not be now after updating to use the iterative approach, but one option could be to use SIMD to ray cast against both triangles at once) Signed-off-by: bosnichd * Fix typos. Signed-off-by: bosnichd * Added a FindNearestIntersectionIterative to use in place of the first-pass FindnearestIntersectionRecursive attempt. Signed-off-by: bosnichd * Remove some functions that are no longer being used. Signed-off-by: bosnichd * Remove a unicode character from a comment to fix the validation build. Signed-off-by: bosnichd * Remove another unicode character from a comment to fix the validation build. Signed-off-by: bosnichd * Update to bail out as soon as t > 1.0f Signed-off-by: bosnichd --- .../AzFramework/Render/IntersectorInterface.h | 2 +- .../Terrain/TerrainDataRequestBus.h | 7 + .../Mocks/Terrain/MockTerrainDataRequestBus.h | 4 + .../Viewport/ViewportMessages.cpp | 13 +- .../TerrainRaycast/TerrainRaycastContext.cpp | 392 ++++++++++++++++++ .../TerrainRaycast/TerrainRaycastContext.h | 62 +++ .../Source/TerrainSystem/TerrainSystem.cpp | 11 + .../Code/Source/TerrainSystem/TerrainSystem.h | 6 + Gems/Terrain/Code/terrain_files.cmake | 2 + 9 files changed, 494 insertions(+), 5 deletions(-) create mode 100644 Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.cpp create mode 100644 Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.h diff --git a/Code/Framework/AzFramework/AzFramework/Render/IntersectorInterface.h b/Code/Framework/AzFramework/AzFramework/Render/IntersectorInterface.h index 44e1290911..10ea51dd75 100644 --- a/Code/Framework/AzFramework/AzFramework/Render/IntersectorInterface.h +++ b/Code/Framework/AzFramework/AzFramework/Render/IntersectorInterface.h @@ -24,7 +24,7 @@ namespace AzFramework //! IntersectorBus::EventResult(result, editorContextId, &IntersectorInterface::RayIntersect, ray); //! //! Raycast against all entities - //! RayResultAggregator rayResult; + //! AZ::EBusReduceResult rayResult; //! IntersectorBus::BroadCastResult(rayResult, &IntersectorInterface::RayIntersect, ray); // class IntersectorInterface diff --git a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h index 8b29f2a554..f9ef264ab1 100644 --- a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h +++ b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include namespace AzFramework @@ -185,6 +187,11 @@ namespace AzFramework SurfacePointRegionFillCallback perPositionCallback, Sampler sampleFilter = Sampler::DEFAULT) const = 0; + //! Get the terrain raycast entity context id. + virtual EntityContextId GetTerrainRaycastEntityContextId() const = 0; + + //! Given a ray, return the closest intersection with terrain. + virtual RenderGeometry::RayResult GetClosestIntersection(const RenderGeometry::RayRequest& ray) const = 0; private: // Private variations of the GetSurfacePoint API exposed to BehaviorContext that returns a value instead of diff --git a/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h b/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h index 52ac28ef63..f5af0ff486 100644 --- a/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h +++ b/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h @@ -102,5 +102,9 @@ namespace UnitTest ProcessSurfaceWeightsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler)); MOCK_CONST_METHOD4( ProcessSurfacePointsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler)); + MOCK_CONST_METHOD0( + GetTerrainRaycastEntityContextId, AzFramework::EntityContextId()); + MOCK_CONST_METHOD1( + GetClosestIntersection, AzFramework::RenderGeometry::RayResult(const AzFramework::RenderGeometry::RayRequest&)); }; } // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp index 24b3c95310..610b9ec854 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp @@ -7,6 +7,7 @@ */ #include +#include #include namespace AzToolsFramework @@ -66,15 +67,19 @@ namespace AzToolsFramework AZ::Vector3 FindClosestPickIntersection(const AzFramework::RenderGeometry::RayRequest& rayRequest, const float defaultDistance) { - AzFramework::RenderGeometry::RayResult renderGeometryIntersectionResult; + // attempt a ray intersection with any visible mesh or terrain and return the intersection position if successful + AZ::EBusReduceResult renderGeometryIntersectionResult; AzFramework::RenderGeometry::IntersectorBus::EventResult( renderGeometryIntersectionResult, AzToolsFramework::GetEntityContextId(), &AzFramework::RenderGeometry::IntersectorBus::Events::RayIntersect, rayRequest); + AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( + renderGeometryIntersectionResult, + &AzFramework::Terrain::TerrainDataRequests::GetClosestIntersection, + rayRequest); - // attempt a ray intersection with any visible mesh and return the intersection position if successful - if (renderGeometryIntersectionResult) + if (renderGeometryIntersectionResult.value) { - return renderGeometryIntersectionResult.m_worldPosition; + return renderGeometryIntersectionResult.value.m_worldPosition; } else { diff --git a/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.cpp b/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.cpp new file mode 100644 index 0000000000..d42388db60 --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include +#include + +using namespace Terrain; + +namespace +{ + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Convenience function to clamp a value to the given grid resolution, rounding up. + inline float ClampToGridRoundUp(float value, float gridResolution) + { + return ceil(value / gridResolution) * gridResolution; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Convenience function to clamp a value to the given grid resolution, rounding down. + inline float ClampToGridRoundDown(float value, float gridResolution) + { + return floor(value / gridResolution) * gridResolution; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Convenience function to find the nearest intersection (if any) between an AABB and a ray. + inline void FindNearestIntersection(const AZ::Aabb& aabb, + const AZ::Vector3& rayStart, + const AZ::Vector3& rayDirection, + const AZ::Vector3& rayDirectionReciprocal, + AzFramework::RenderGeometry::RayResult& result) + { + float intersectionT; + float intersectionEndT; + AZ::Vector3 intersectionNormal; + const int intersectionResult = AZ::Intersect::IntersectRayAABB(rayStart, + rayDirection, + rayDirectionReciprocal, + aabb, + intersectionT, + intersectionEndT, + intersectionNormal); + if (intersectionResult != AZ::Intersect::ISECT_RAY_AABB_NONE) + { + result.m_worldPosition = rayStart + (rayDirection * intersectionT); + result.m_worldNormal = intersectionNormal; + result.m_distance = rayDirection.GetLength() * intersectionT; + } + else + { + result.m_distance = FLT_MAX; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Convenience function to find the nearest intersection (if any) between a triangle and a ray. + // This is an implementation of the Moller-Trumbore intersection algorithm. I first attempted to use + // the existing AZ::Intersect::IntersectSegmentTriangleCCW, which appears to use the same algorithm, + // but it takes a line segment as opposed to a ray and was not returning the expected results. Once + // I've written some tests I can go back and try it again to figure out what is different, but this + // is all likely to get replaced with an optimized SIMD version anyway so this should be ok for now. + inline void FindNearestIntersection(const AZ::Vector3& vertexA, + const AZ::Vector3& vertexB, + const AZ::Vector3& vertexC, + const AZ::Vector3& rayStart, + const AZ::Vector3& rayDirection, + AzFramework::RenderGeometry::RayResult& result) + { + const AZ::Vector3 edgeAB = vertexB - vertexA; + const AZ::Vector3 edgeAC = vertexC - vertexA; + const AZ::Vector3 pVec = rayDirection.Cross(edgeAC); + const float det = edgeAB.Dot(pVec); + if (AZ::IsClose(det, 0.0f)) + { + // The ray is parallel to the triangle. + return; + } + + const float detInv = 1.0f / det; + const AZ::Vector3 tVec = rayStart - vertexA; + const float u = detInv * tVec.Dot(pVec); + if (u < 0.0f || u > 1.0f) + { + // No intersection. + return; + } + + const AZ::Vector3 qVec = tVec.Cross(edgeAB); + const float v = detInv * rayDirection.Dot(qVec); + if (v < 0.0 || u + v > 1.0) + { + // No intersection. + return; + } + + const float t = detInv * edgeAC.Dot(qVec); + if (t > FLT_EPSILON) + { + result.m_worldPosition = rayStart + (rayDirection * t); + result.m_worldNormal = edgeAB.Cross(edgeAC); + result.m_distance = rayDirection.GetLength() * t; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Convenience function to get the terrain height values at each corner of an AABB, triangulate them, + // and then find the nearest intersection (if any) between the resulting triangles and the given ray. + inline void TriangulateAndFindNearestIntersection(const TerrainSystem& terrainSystem, + const AZ::Aabb& aabb, + const AZ::Vector3& rayStart, + const AZ::Vector3& rayDirection, + const AZ::Vector3& rayDirectionReciprocal, + AzFramework::RenderGeometry::RayResult& result) + { + // Obtain the height values at each corner of the AABB. + const AZ::Vector3& aabbMin = aabb.GetMin(); + const AZ::Vector3& aabbMax = aabb.GetMax(); + AZ::Vector3 point0 = aabbMin; + AZ::Vector3 point2 = aabbMax; + AZ::Vector3 point1(point0.GetX(), point2.GetY(), 0.0f); + AZ::Vector3 point3(point2.GetX(), point0.GetY(), 0.0f); + point0.SetZ(terrainSystem.GetHeight(point0, AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT)); + point1.SetZ(terrainSystem.GetHeight(point1, AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT)); + point2.SetZ(terrainSystem.GetHeight(point2, AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT)); + point3.SetZ(terrainSystem.GetHeight(point3, AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT)); + + // Construct a smaller AABB that tightly encloses the four terrain points. + const float refinedMinZ = AZStd::GetMin(AZStd::GetMin(AZStd::GetMin(point0.GetZ(), point1.GetZ()), point2.GetZ()), point3.GetZ()); + const float refinedMaxZ = AZStd::GetMax(AZStd::GetMax(AZStd::GetMax(point0.GetZ(), point1.GetZ()), point2.GetZ()), point3.GetZ()); + const AZ::Vector3 refinedMin(aabbMin.GetX(), aabbMin.GetY(), refinedMinZ); + const AZ::Vector3 refinedMax(aabbMax.GetX(), aabbMax.GetY(), refinedMaxZ); + const AZ::Aabb refinedAABB = AZ::Aabb::CreateFromMinMax(refinedMin, refinedMax); + + // Check for a hit against the refined AABB. + float intersectionT; + float intersectionEndT; + const int intersectionResult = AZ::Intersect::IntersectRayAABB2(rayStart, + rayDirectionReciprocal, + refinedAABB, + intersectionT, + intersectionEndT); + if (intersectionResult == AZ::Intersect::ISECT_RAY_AABB_NONE) + { + return; + } + + // Finally, triangulate the four terrain points and check for a hit, + // splitting using the top-left -> bottom-right diagonal so to match + // the current behavior of the terrain physics and rendering systems. + AzFramework::RenderGeometry::RayResult bottomLeftIntersectionResult; + FindNearestIntersection(rayStart, + rayDirection, + point0, + point3, + point1, + bottomLeftIntersectionResult); + + AzFramework::RenderGeometry::RayResult topRightIntersectionResult; + FindNearestIntersection(rayStart, + rayDirection, + point2, + point1, + point3, + topRightIntersectionResult); + + if (bottomLeftIntersectionResult) + { + result = !topRightIntersectionResult || bottomLeftIntersectionResult.m_distance < topRightIntersectionResult.m_distance ? + bottomLeftIntersectionResult : + topRightIntersectionResult; + } + else if (topRightIntersectionResult) + { + result = topRightIntersectionResult; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Iterative function that divides an AABB encompasing terrain points into columns (or a voxel grid) + // of size equal to the given grid resolution, steps along the ray visiting each voxel it intersects + // in order from nearest to farthest, then obtains the terrain height values at each corner in order + // to triangulate them and find the nearest intersection (if any) between the triangles and the ray. + // + // Visualization: + // - X: Column intersection but no triangle hit found + // - T: Column intersection with a triangle hit found + // ________________________________________ + // | | | | | | | | | + // |____|____|____|____|____|____|____|____| Ray + // | | | | | | | | | / + // |____|____|____|____|____|____|____|____| / + // | | | | | | | | X |/ + // |____|____|____|____|____|____|____|____/ + // | | | | | | | | X /| + // |____|____|____|____|____|____|____|__/_| + // | | | | | | | | /X | + // |____|____|____|____|____|____|____|/___| + // | | | | | | | X / X | + // |____|____|____|____|____|____|___/|____| + // | | | | | | | T/ | | + // |____|____|____|____|____|____|____|____| + // | | | | | | | | | + // |____|____|____|____|____|____|____|____| + inline void FindNearestIntersectionIterative(const TerrainSystem& terrainSystem, + const AZ::Vector2& terrainResolution, + const AZ::Aabb& terrainWorldBounds, + const AZ::Vector3& rayStart, + const AZ::Vector3& rayEnd, + AzFramework::RenderGeometry::RayResult& result) + { + // Find the nearest intersection (if any) between the ray and terrain world bounds. + // Note that the ray might (and often will) start inside the terrain world bounds. + const AZ::Vector3 rayDirection = rayEnd - rayStart; + const AZ::Vector3 rayDirectionReciprocal = rayDirection.GetReciprocal(); + FindNearestIntersection(terrainWorldBounds, + rayStart, + rayDirection, + rayDirectionReciprocal, + result); + if (!result) + { + // The ray does not intersect the terrain world bounds. + return; + } + + // The terrain world can be visualized as a grid of columns, + // where the terrain resolution determines the dimensions of + // each column, or a voxel grid with one cell in z dimension. + // + // Starting at the voxel containing the initial intersection, + // we want to step along the ray and visit each voxel the ray + // intersects in order from nearest to furthest until we find + // an intersection with the terrain or the ray exits the grid. + const AZ::Vector3& initialIntersection = result.m_worldPosition; + const float initialIntersectionX = initialIntersection.GetX(); + const float initialIntersectionY = initialIntersection.GetY(); + const float initialIntersectionZ = initialIntersection.GetZ(); + const float gridResolutionX = terrainResolution.GetX(); + const float gridResolutionY = terrainResolution.GetY(); + const float gridResolutionZ = terrainWorldBounds.GetMax().GetZ() - terrainWorldBounds.GetMin().GetZ(); + float initialVoxelMinX = ClampToGridRoundDown(initialIntersectionX, gridResolutionX); + float initialVoxelMinY = ClampToGridRoundDown(initialIntersectionY, gridResolutionY); + float initialVoxelMinZ = terrainWorldBounds.GetMin().GetZ(); + float initialVoxelMaxX = ClampToGridRoundUp(initialIntersectionX, gridResolutionX); + float initialVoxelMaxY = ClampToGridRoundUp(initialIntersectionY, gridResolutionY); + float initialVoxelMaxZ = terrainWorldBounds.GetMax().GetZ(); + + // For each axis calculate the distance t we need to move along + // the ray in order to fully traverse a voxel in that dimension. + const float rayDirectionX = rayDirection.GetX(); + const float rayDirectionY = rayDirection.GetY(); + const float rayDirectionZ = rayDirection.GetZ(); + const float stepX = AZ::GetSign(rayDirectionX) * gridResolutionX; + const float stepY = AZ::GetSign(rayDirectionY) * gridResolutionY; + const float stepZ = AZ::GetSign(rayDirectionZ) * gridResolutionZ; + const float tDeltaX = rayDirectionX ? + stepX / rayDirectionX : + std::numeric_limits::max(); + const float tDeltaY = rayDirectionY ? + stepY / rayDirectionY : + std::numeric_limits::max(); + const float tDeltaZ = rayDirectionZ ? + stepZ / rayDirectionZ : + std::numeric_limits::max(); + + // For each axis, calculate the distance t we need to move along the ray + // from the initial intersection point to the next voxel along that axis. + const float offsetX = stepX < 0.0f ? + initialVoxelMinX - initialIntersectionX : + initialVoxelMaxX - initialIntersectionX; + const float offsetY = stepY < 0.0f ? + initialVoxelMinY - initialIntersectionY : + initialVoxelMaxY - initialIntersectionY; + const float offsetZ = stepZ < 0.0f ? + initialVoxelMinZ - initialIntersectionZ : + initialVoxelMaxZ - initialIntersectionZ; + float tMaxX = rayDirectionX ? + offsetX / rayDirectionX : + std::numeric_limits::max(); + float tMaxY = rayDirectionY ? + offsetY / rayDirectionY : + std::numeric_limits::max(); + float tMaxZ = rayDirectionZ ? + offsetZ / rayDirectionZ : + std::numeric_limits::max(); + + // Calculate the min/max voxel grid value on each axis by expanding + // the terrain world bounds so they align with the grid resolution. + const float voxelGridMinX = ClampToGridRoundDown(terrainWorldBounds.GetMin().GetX(), gridResolutionX); + const float voxelGridMinY = ClampToGridRoundDown(terrainWorldBounds.GetMin().GetY(), gridResolutionY); + const float voxelGridMinZ = terrainWorldBounds.GetMin().GetZ(); + const float voxelGridMaxX = ClampToGridRoundUp(terrainWorldBounds.GetMax().GetX(), gridResolutionX); + const float voxelGridMaxY = ClampToGridRoundUp(terrainWorldBounds.GetMax().GetY(), gridResolutionY); + const float voxelGridMaxZ = terrainWorldBounds.GetMax().GetZ(); + + // Using the initial voxel values, construct an AABB representing the current voxel, + // then grab references to AABBs min/max vectors so we can manipulate them directly. + AZ::Aabb currentVoxel = AZ::Aabb::CreateFromMinMax({initialVoxelMinX, initialVoxelMinY, initialVoxelMinZ}, + {initialVoxelMaxX, initialVoxelMaxY, initialVoxelMaxZ}); + AZ::Vector3& currentVoxelMin = const_cast(currentVoxel.GetMin()); + AZ::Vector3& currentVoxelMax = const_cast(currentVoxel.GetMax()); + const AZ::Vector3 stepVecX(stepX, 0.0f, 0.0f); + const AZ::Vector3 stepVecY(0.0f, stepY, 0.0f); + const AZ::Vector3 stepVecZ(0.0f, 0.0f, stepZ); + + // Now we can step along the ray and visit each voxel the ray + // intersects in order from nearest to furthest until we find + // an intersection with the terrain or the ray exits the grid. + result = AzFramework::RenderGeometry::RayResult(); + while (currentVoxel.GetMin().GetX() <= voxelGridMaxX && + currentVoxel.GetMax().GetX() >= voxelGridMinX && + currentVoxel.GetMin().GetY() <= voxelGridMaxY && + currentVoxel.GetMax().GetY() >= voxelGridMinY && + currentVoxel.GetMin().GetZ() <= voxelGridMaxZ && + currentVoxel.GetMax().GetZ() >= voxelGridMinZ && + tMaxX <= 1.0f && tMaxY <= 1.0f && tMaxZ <= 1.0f) + { + TriangulateAndFindNearestIntersection(terrainSystem, + currentVoxel, + rayStart, + rayDirection, + rayDirectionReciprocal, + result); + if (result) + { + // Intersection found. + break; + } + + // Step to the next voxel. + if (tMaxX < tMaxY && tMaxX < tMaxZ) + { + currentVoxelMin += stepVecX; + currentVoxelMax += stepVecX; + tMaxX += tDeltaX; + } + else if (tMaxY < tMaxZ) + { + currentVoxelMin += stepVecY; + currentVoxelMax += stepVecY; + tMaxY += tDeltaY; + } + else + { + currentVoxelMin += stepVecZ; + currentVoxelMax += stepVecZ; + tMaxZ += tDeltaZ; + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +TerrainRaycastContext::TerrainRaycastContext(TerrainSystem& terrainSystem) + : m_terrainSystem(terrainSystem) + , m_entityContextId(AzFramework::EntityContextId::CreateRandom()) +{ + AzFramework::RenderGeometry::IntersectorBus::Handler::BusConnect(m_entityContextId); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +TerrainRaycastContext::~TerrainRaycastContext() +{ + AzFramework::RenderGeometry::IntersectorBus::Handler::BusDisconnect(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +AzFramework::RenderGeometry::RayResult TerrainRaycastContext::RayIntersect( + const AzFramework::RenderGeometry::RayRequest& ray) +{ + const AZ::Aabb terrainWorldBounds = m_terrainSystem.GetTerrainAabb(); + const AZ::Vector2 terrainResolution = m_terrainSystem.GetTerrainHeightQueryResolution(); + AzFramework::RenderGeometry::RayResult rayIntersectionResult; + FindNearestIntersectionIterative(m_terrainSystem, + terrainResolution, + terrainWorldBounds, + ray.m_startWorldPosition, + ray.m_endWorldPosition, + rayIntersectionResult); + + // If needed we could call m_terrainSystem.FindBestAreaEntityAtPosition in order to set + // rayIntersectionResult.m_entityAndComponent, but I'm not sure whether that is correct. + return rayIntersectionResult; +} diff --git a/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.h b/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.h new file mode 100644 index 0000000000..a5a50848c3 --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////// +namespace Terrain +{ + class TerrainSystem; + + //////////////////////////////////////////////////////////////////////////////////////////////// + class TerrainRaycastContext : public AzFramework::RenderGeometry::IntersectorBus::Handler + { + public: + //////////////////////////////////////////////////////////////////////////////////////////// + //! Constructor + //! \param[in] terrainSystem The terrain system that owns this terrain raycast context + TerrainRaycastContext(TerrainSystem& terrainSystem); + + //////////////////////////////////////////////////////////////////////////////////////////// + // Disable copying + AZ_DISABLE_COPY_MOVE(TerrainRaycastContext); + + //////////////////////////////////////////////////////////////////////////////////////////// + //! Destructor + ~TerrainRaycastContext(); + + //////////////////////////////////////////////////////////////////////////////////////////// + //! Access to the terrain raycast context's entity context id + //! \return The terrain raycast context's entity context id + inline AzFramework::EntityContextId GetEntityContextId() const { return m_entityContextId; } + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::RenderGeometry::RayIntersect + AzFramework::RenderGeometry::RayResult RayIntersect(const AzFramework::RenderGeometry::RayRequest& ray) override; + + protected: + //////////////////////////////////////////////////////////////////////////////////////////// + // RenderGeometry::IntersectorBus inherits from RenderGeometry::IntersectionNotifications, + // so we must override the following pure virtual functions. We could potentially implement + // them using TerrainSystem::m_registeredAreas, but right now that would not serve a purpose. + ///@{ + //! Unused pure virtual override + void OnEntityConnected(AZ::EntityId) override {} + void OnEntityDisconnected(AZ::EntityId) override {} + void OnGeometryChanged(AZ::EntityId) override {} + ///@} + + private: + //////////////////////////////////////////////////////////////////////////////////////////// + // Variables + TerrainSystem& m_terrainSystem; //!< Terrain system that owns this terrain raycast context + AzFramework::EntityContextId m_entityContextId; //!< This object's entity context id + }; +} // namespace Terrain diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp index 4dfa03ed53..35e6992db3 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp @@ -51,6 +51,7 @@ bool TerrainLayerPriorityComparator::operator()(const AZ::EntityId& layer1id, co } TerrainSystem::TerrainSystem() + : m_terrainRaycastContext(*this) { Terrain::TerrainSystemServiceRequestBus::Handler::BusConnect(); AZ::TickBus::Handler::BusConnect(); @@ -438,6 +439,16 @@ void TerrainSystem::GetSurfacePointFromFloats( GetSurfacePoint(AZ::Vector3(x, y, 0.0f), outSurfacePoint, sampleFilter, terrainExistsPtr); } +AzFramework::EntityContextId TerrainSystem::GetTerrainRaycastEntityContextId() const +{ + return m_terrainRaycastContext.GetEntityContextId(); +} + +AzFramework::RenderGeometry::RayResult TerrainSystem::GetClosestIntersection( + const AzFramework::RenderGeometry::RayRequest& ray) const +{ + return m_terrainRaycastContext.RayIntersect(ray); +} AZ::EntityId TerrainSystem::FindBestAreaEntityAtPosition(float x, float y, AZ::Aabb& bounds) const { diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h index 3e489730d0..1cdb6e52b1 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h @@ -23,6 +23,7 @@ #include #include +#include #include namespace Terrain @@ -187,6 +188,9 @@ namespace Terrain AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback, Sampler sampleFilter = Sampler::DEFAULT) const override; + AzFramework::EntityContextId GetTerrainRaycastEntityContextId() const override; + AzFramework::RenderGeometry::RayResult GetClosestIntersection( + const AzFramework::RenderGeometry::RayRequest& ray) const override; private: void ClampPosition(float x, float y, AZ::Vector2& outPosition, AZ::Vector2& normalizedDelta) const; @@ -230,5 +234,7 @@ namespace Terrain mutable AZStd::shared_mutex m_areaMutex; AZStd::map m_registeredAreas; + + mutable TerrainRaycastContext m_terrainRaycastContext; }; } // namespace Terrain diff --git a/Gems/Terrain/Code/terrain_files.cmake b/Gems/Terrain/Code/terrain_files.cmake index ab19d33618..4b994c2587 100644 --- a/Gems/Terrain/Code/terrain_files.cmake +++ b/Gems/Terrain/Code/terrain_files.cmake @@ -27,6 +27,8 @@ set(FILES Source/Components/TerrainWorldDebuggerComponent.h Source/Components/TerrainWorldRendererComponent.cpp Source/Components/TerrainWorldRendererComponent.h + Source/TerrainRaycast/TerrainRaycastContext.cpp + Source/TerrainRaycast/TerrainRaycastContext.h Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp From 640fe70c56f7a5aaaf244d9913f88acc6899fd16 Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Mon, 24 Jan 2022 15:09:15 -0600 Subject: [PATCH 19/20] Combining the original scene manifest with the new manifest (#7083) * Combining the original scene manifest with the new manifest to allow the OnPrepareForExport to execute Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> * fixing comment Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> --- .../Blast/Editor/Scripts/blast_asset_builder.py | 2 +- .../Editor/Scripts/blast_chunk_processor.py | 17 ++++++++++++++--- Gems/Blast/Editor/Scripts/bootstrap.py | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Gems/Blast/Editor/Scripts/blast_asset_builder.py b/Gems/Blast/Editor/Scripts/blast_asset_builder.py index a570489ed1..cd17360f9f 100644 --- a/Gems/Blast/Editor/Scripts/blast_asset_builder.py +++ b/Gems/Blast/Editor/Scripts/blast_asset_builder.py @@ -15,7 +15,7 @@ manifest that writes out asset chunk data for .blast files import os, traceback, binascii, sys, json, pathlib import azlmbr.math import azlmbr.asset -import azlmbr.asset.entity +import azlmbr.entity import azlmbr.asset.builder import azlmbr.bus diff --git a/Gems/Blast/Editor/Scripts/blast_chunk_processor.py b/Gems/Blast/Editor/Scripts/blast_chunk_processor.py index d112f465e9..500577716b 100644 --- a/Gems/Blast/Editor/Scripts/blast_chunk_processor.py +++ b/Gems/Blast/Editor/Scripts/blast_chunk_processor.py @@ -12,10 +12,10 @@ into a scene manifest This is also a SceneAPI script that executes from a foo.fbx.assetinfo scene manifest that writes out asset chunk data for .blast files """ -import os, traceback, binascii, sys, json, pathlib +import os, traceback, binascii, sys, json, pathlib, logging import azlmbr.math import azlmbr.asset -import azlmbr.asset.entity +import azlmbr.entity import azlmbr.asset.builder import azlmbr.bus @@ -24,6 +24,14 @@ import azlmbr.bus # blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0) +def log_exception_traceback(): + """ + Outputs an exception stacktrace. + """ + data = traceback.format_exc() + logger = logging.getLogger('python') + logger.error(data) + def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList): import azlmbr.scene import azlmbr.object @@ -97,7 +105,7 @@ def get_mesh_node_names(sceneGraph): return meshDataList def update_manifest(scene): - import uuid, os + import uuid, os, json import azlmbr.scene as sceneApi import azlmbr.scene.graph from scene_api import scene_data as sceneData @@ -116,6 +124,9 @@ def update_manifest(scene): meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}' sceneManifest.mesh_group_select_node(meshGroup, chunkPath) + # combine both scene manifests so the OnPrepareForExport will be called + originalManifest = json.loads(scene.manifest.ExportToJson()) + sceneManifest.manifest["values"].append(originalManifest["values"][0]) return sceneManifest.export() sceneJobHandler = None diff --git a/Gems/Blast/Editor/Scripts/bootstrap.py b/Gems/Blast/Editor/Scripts/bootstrap.py index 93004d474f..aa7e7625e8 100755 --- a/Gems/Blast/Editor/Scripts/bootstrap.py +++ b/Gems/Blast/Editor/Scripts/bootstrap.py @@ -6,7 +6,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT """ try: import azlmbr.asset - import azlmbr.asset.entity + import azlmbr.entity import azlmbr.asset.builder import blast_asset_builder except: From d1143770e0f985d00ae743614334db761c9f329e Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Mon, 24 Jan 2022 13:17:16 -0800 Subject: [PATCH 20/20] Prefab Focus Mode | Fixes to viewport top toolbar (#7094) * Fixes to the viewport top toolbar. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Additional checks to prevent issues if widgets aren't set up correctly. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Add asserts to catch UI changes that would break this class. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- Code/Editor/ViewPane.cpp | 37 +++++++++---------- Code/Editor/ViewportTitleDlg.cpp | 24 +++++++++--- Code/Editor/ViewportTitleDlg.h | 2 + Code/Editor/ViewportTitleDlg.ui | 15 ++++++++ .../AzQtComponents/Components/ToolBarArea.cpp | 3 +- .../Prefab/PrefabViewportFocusPathHandler.cpp | 3 ++ 6 files changed, 57 insertions(+), 27 deletions(-) diff --git a/Code/Editor/ViewPane.cpp b/Code/Editor/ViewPane.cpp index 90b44d9c9d..99b4c5a1cc 100644 --- a/Code/Editor/ViewPane.cpp +++ b/Code/Editor/ViewPane.cpp @@ -87,29 +87,15 @@ public: } // Handle labels with submenus - if (auto toolLabel = qobject_cast(toolWidget)) + if (auto toolLabel = qobject_cast(toolWidget)) { if (!toolLabel->isVisible()) { // Manually turn the custom context menus into submenus - if (toolLabel->objectName() == "m_fovStaticCtrl") + if (toolLabel->menu()) { - QAction* newAction = menu->addMenu(m_viewportDlg->GetFovMenu()); - newAction->setText(QString("FOV: %1").arg(toolLabel->text())); - } - else if (toolLabel->objectName() == "m_ratioStaticCtrl") - { - QAction* newAction = menu->addMenu(m_viewportDlg->GetAspectMenu()); - newAction->setText(QString("Ratio: %1").arg(toolLabel->text())); - } - else if (toolLabel->objectName() == "m_sizeStaticCtrl") - { - QAction* newAction = menu->addMenu(m_viewportDlg->GetResolutionMenu()); - newAction->setText(QString("%1").arg(toolLabel->text())); - } - else - { - // Don't add actions for other Labels + QAction* action = menu->addMenu(toolLabel->menu()); + action->setText(toolLabel->text()); continue; } } @@ -179,14 +165,25 @@ CLayoutViewPane::CLayoutViewPane(QWidget* parent) toolbar->installEventFilter(&m_viewportTitleDlg); toolbar->setContextMenuPolicy(Qt::CustomContextMenu); connect(toolbar, &QWidget::customContextMenuRequested, &m_viewportTitleDlg, &QWidget::customContextMenuRequested); - setContextMenuPolicy(Qt::NoContextMenu); - + if (QToolButton* expansion = AzQtComponents::ToolBar::getToolBarExpansionButton(toolbar)) { expansion->installEventFilter(m_expanderWatcher); } + AzQtComponents::BreadCrumbs* prefabsBreadcrumbs = + qobject_cast(toolbar->findChild("m_prefabFocusPath")); + QToolButton* backButton = qobject_cast(toolbar->findChild("m_prefabFocusBackButton")); + + AZ_Assert(prefabsBreadcrumbs, "Could not find Prefabs Breadcrumbs widget on CLayoutViewPane initialization!"); + AZ_Assert(backButton, "Could not find Prefabs Breadcrumbs back button on CLayoutViewPane initialization!"); + + if (prefabsBreadcrumbs && backButton) + { + m_viewportTitleDlg.InitializePrefabViewportFocusPathHandler(prefabsBreadcrumbs, backButton); + } + m_id = -1; } diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 90aa044d25..bbd9eaaa10 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -383,12 +383,7 @@ void CViewportTitleDlg::OnInitDialog() bool isPrefabSystemEnabled = false; AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); - if (isPrefabSystemEnabled) - { - m_prefabViewportFocusPathHandler = new AzToolsFramework::Prefab::PrefabViewportFocusPathHandler(); - m_prefabViewportFocusPathHandler->Initialize(m_ui->m_prefabFocusPath, m_ui->m_prefabFocusBackButton); - } - else + if (!isPrefabSystemEnabled) { m_ui->m_prefabFocusPath->setEnabled(false); m_ui->m_prefabFocusBackButton->setEnabled(false); @@ -397,6 +392,23 @@ void CViewportTitleDlg::OnInitDialog() } } +void CViewportTitleDlg::InitializePrefabViewportFocusPathHandler(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton) +{ + if (m_prefabViewportFocusPathHandler != nullptr) + { + return; + } + + bool isPrefabSystemEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); + + if (isPrefabSystemEnabled) + { + m_prefabViewportFocusPathHandler = new AzToolsFramework::Prefab::PrefabViewportFocusPathHandler(); + m_prefabViewportFocusPathHandler->Initialize(breadcrumbsWidget, backButton); + } +} + ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::SetTitle(const QString& title) { diff --git a/Code/Editor/ViewportTitleDlg.h b/Code/Editor/ViewportTitleDlg.h index b8da7f20ea..8d8b06b96d 100644 --- a/Code/Editor/ViewportTitleDlg.h +++ b/Code/Editor/ViewportTitleDlg.h @@ -70,6 +70,8 @@ public: QMenu* const GetAspectMenu(); QMenu* const GetResolutionMenu(); + void InitializePrefabViewportFocusPathHandler(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton); + Q_SIGNALS: void ActionTriggered(int command); diff --git a/Code/Editor/ViewportTitleDlg.ui b/Code/Editor/ViewportTitleDlg.ui index 7ba6361cf9..1711bdaf90 100644 --- a/Code/Editor/ViewportTitleDlg.ui +++ b/Code/Editor/ViewportTitleDlg.ui @@ -80,6 +80,9 @@ Camera settings + + Camera settings + :/Menu/camera.svg:/Menu/camera.svg @@ -91,6 +94,9 @@ Debug information + + Debug information + :/Menu/debug.svg:/Menu/debug.svg @@ -105,6 +111,9 @@ Toggle viewport helpers + + Toggle viewport helpers + :/Menu/helpers.svg:/Menu/helpers.svg @@ -119,6 +128,9 @@ Viewport resolution + + Viewport resolution + :/Menu/resolution.svg:/Menu/resolution.svg @@ -130,6 +142,9 @@ Other settings + + Other settings + :/Menu/menu.svg:/Menu/menu.svg diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToolBarArea.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToolBarArea.cpp index b1ef0a670b..14633dcb78 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToolBarArea.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToolBarArea.cpp @@ -32,7 +32,8 @@ namespace AzQtComponents { if (QWidget* widget = item->widget()) { - toolbar->addWidget(widget); + QAction* action = toolbar->addWidget(widget); + action->setObjectName(widget->objectName()); } else if (item->spacerItem()) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index c1fc9138d1..275079371a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -73,6 +73,9 @@ namespace AzToolsFramework::Prefab { // Push new Path m_breadcrumbsWidget->pushPath(m_prefabFocusPublicInterface->GetPrefabFocusPath(m_editorEntityContextId).c_str()); + + // If root instance is focused, disable the back button; else enable it. + m_backButton->setEnabled(m_prefabFocusPublicInterface->GetPrefabFocusPathLength(m_editorEntityContextId) > 1); } } // namespace AzToolsFramework::Prefab