From 5b88d96eec29a5b6359243f5413693f3acf619f0 Mon Sep 17 00:00:00 2001 From: Kyle B Date: Mon, 2 Aug 2021 13:36:10 -0700 Subject: [PATCH 01/26] Exposed fields to the mesh component giving greater Lod control from the editor Signed-off-by: Kyle B --- .../Atom/Feature/Mesh/MeshFeatureProcessor.h | 12 ++- .../Mesh/MeshFeatureProcessorInterface.h | 7 ++ .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 74 +++++++++++++++++-- .../Code/Include/Atom/RPI.Public/Culling.h | 5 ++ .../CommonFeatures/Mesh/MeshComponentBus.h | 6 ++ .../Code/Source/Mesh/EditorMeshComponent.cpp | 7 ++ .../Source/Mesh/MeshComponentController.cpp | 32 ++++++++ .../Source/Mesh/MeshComponentController.h | 7 ++ .../Code/Source/AtomActorInstance.cpp | 20 +++++ .../Code/Source/AtomActorInstance.h | 4 + 10 files changed, 167 insertions(+), 7 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index a2d9517ec4..3cdff52ba7 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -63,8 +63,12 @@ namespace AZ void SetRayTracingData(); void SetSortKey(RHI::DrawItemSortKey sortKey); RHI::DrawItemSortKey GetSortKey(); - void SetLodOverride(RPI::Cullable::LodOverride lodOverride); + void SetLodOverride( RPI::Cullable::LodOverride lodOverride); RPI::Cullable::LodOverride GetLodOverride(); + void SetMinimumScreenCoverage(float minimumScreenCoverage); + float GetMinimumScreenCoverage(); + void SetQualityDecayRate(float qualityDecayRate); + float GetQualityDecayRate(); void UpdateDrawPackets(bool forceUpdate = false); void BuildCullable(); void UpdateCullBounds(const TransformServiceFeatureProcessor* transformService); @@ -158,6 +162,12 @@ namespace AZ void SetLodOverride(const MeshHandle& meshHandle, RPI::Cullable::LodOverride lodOverride) override; RPI::Cullable::LodOverride GetLodOverride(const MeshHandle& meshHandle) override; + void SetMinimumScreenCoverage(const MeshHandle& meshHandle, float minimumScreenCoverage) override; + float GetMinimumScreenCoverage(const MeshHandle& meshHandle) override; + + void SetQualityDecayRate(const MeshHandle& meshHandle, float qualityDecayRate) override; + float GetQualityDecayRate(const MeshHandle& meshHandle) override; + void SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps) override; void SetRayTracingEnabled(const MeshHandle& meshHandle, bool rayTracingEnabled) override; void SetVisible(const MeshHandle& meshHandle, bool visible) override; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h index 4e74302276..b71b420625 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h @@ -98,6 +98,13 @@ namespace AZ virtual void SetLodOverride(const MeshHandle& meshHandle, RPI::Cullable::LodOverride lodOverride) = 0; //! Gets the LOD override for a given mesh handle. virtual RPI::Cullable::LodOverride GetLodOverride(const MeshHandle& meshHandle) = 0; + + virtual void SetMinimumScreenCoverage(const MeshHandle& meshHandle, float minimumScreenCoverage) = 0; + virtual float GetMinimumScreenCoverage(const MeshHandle& meshHandle) = 0; + + virtual void SetQualityDecayRate(const MeshHandle& meshHandle, float qualityDecayRate) = 0; + virtual float GetQualityDecayRate(const MeshHandle& meshHandle) = 0; + //! Sets the option to exclude this mesh from baked reflection probe cubemaps virtual void SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps) = 0; //! Sets the option to exclude this mesh from raytracing diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index c6362f3a5d..ce8ead9318 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -380,6 +380,48 @@ namespace AZ } } + void MeshFeatureProcessor::SetMinimumScreenCoverage( const MeshHandle& meshHandle, float minimumScreenCoverage) + { + if (meshHandle.IsValid()) + { + meshHandle->SetMinimumScreenCoverage(minimumScreenCoverage); + } + } + + float MeshFeatureProcessor::GetMinimumScreenCoverage(const MeshHandle& meshHandle) + { + if (meshHandle.IsValid()) + { + return meshHandle->GetMinimumScreenCoverage(); + } + else + { + AZ_Assert(false, "Invalid mesh handle"); + return 0; + } + } + + void MeshFeatureProcessor::SetQualityDecayRate(const MeshHandle& meshHandle, float qualityDecayRate) + { + if (meshHandle.IsValid()) + { + meshHandle->SetQualityDecayRate(qualityDecayRate); + } + } + + float MeshFeatureProcessor::GetQualityDecayRate(const MeshHandle& meshHandle) + { + if (meshHandle.IsValid()) + { + return meshHandle->GetQualityDecayRate(); + } + else + { + AZ_Assert(false, "Invalid mesh handle"); + return 0; + } + } + void MeshFeatureProcessor::SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps) { if (meshHandle.IsValid()) @@ -1001,6 +1043,26 @@ namespace AZ return m_cullable.m_lodData.m_lodOverride; } + void MeshDataInstance::SetMinimumScreenCoverage(float minimumScreenCoverage) + { + m_cullable.m_lodData.m_minimumScreenCoverage = minimumScreenCoverage; + } + + float MeshDataInstance::GetMinimumScreenCoverage() + { + return m_cullable.m_lodData.m_minimumScreenCoverage; + } + + void MeshDataInstance::SetQualityDecayRate(float qualityDecayRate) + { + m_cullable.m_lodData.m_qualityDecayRate = qualityDecayRate; + } + + float MeshDataInstance::GetQualityDecayRate() + { + return m_cullable.m_lodData.m_qualityDecayRate; + } + void MeshDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/) { AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender); @@ -1036,13 +1098,11 @@ namespace AZ cullData.m_drawListMask.reset(); const size_t lodCount = lodAssets.size(); + for (size_t lodIndex = 0; lodIndex < lodCount; ++lodIndex) { //initialize the lod RPI::Cullable::LodData::Lod& lod = lodData.m_lods[lodIndex]; - //[GFX TODO][ATOM-5562] - Level of detail: override lod distances and add global lod multiplier(s) - static const float MinimumScreenCoverage = 1.0f/1080.0f; //mesh should cover at least a screen pixel at 1080p to be drawn - static const float ReductionFactor = 0.5f; if (lodIndex == 0) { //first lod @@ -1051,17 +1111,19 @@ namespace AZ else { //every other lod: use the previous lod's min - lod.m_screenCoverageMax = AZStd::GetMax(lodData.m_lods[lodIndex-1].m_screenCoverageMin, MinimumScreenCoverage); + lod.m_screenCoverageMax = AZStd::GetMax(lodData.m_lods[lodIndex - 1].m_screenCoverageMin, lodData.m_minimumScreenCoverage); } + if (lodIndex < lodAssets.size() - 1) { //first and middle lods: compute a stepdown value for the min - lod.m_screenCoverageMin = AZStd::GetMax(ReductionFactor * lod.m_screenCoverageMax, MinimumScreenCoverage); + lod.m_screenCoverageMin = + AZStd::GetMax(lodData.m_qualityDecayRate * lod.m_screenCoverageMax, lodData.m_minimumScreenCoverage); } else { //last lod: use MinimumScreenCoverage for the min - lod.m_screenCoverageMin = MinimumScreenCoverage; + lod.m_screenCoverageMin = lodData.m_minimumScreenCoverage; } lod.m_drawPackets.clear(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h index bcc4dfb89f..30cf091735 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -88,6 +88,11 @@ namespace AZ //! Suggest setting to: 0.5f*localAabb.GetExtents().GetMaxElement() float m_lodSelectionRadius = 1.0f; + // the minimum possibe area a sphere enclosing a mesh projected onto the screen should have before it is culled. + float m_minimumScreenCoverage = 1.0f / 1080.0f; + // The screen area decay between 0 and 1, i.e. closer to 1 -> lose quality immediately, closer to 0 -> never lose quality + float m_qualityDecayRate = 0.5f; + LodOverride m_lodOverride = NoLodOverride; }; LodData m_lodData; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h index ff75f7f45a..baef507b7a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h @@ -39,6 +39,12 @@ namespace AZ virtual void SetLodOverride(RPI::Cullable::LodOverride lodOverride) = 0; virtual RPI::Cullable::LodOverride GetLodOverride() const = 0; + virtual void SetMinimumScreenCoverage(float minimumScreenCoverage) = 0; + virtual float GetMinimumScreenCoverage() const = 0; + + virtual void SetQualityDecayRate(float qualityDecayRate) = 0; + virtual float GetQualityDecayRate() const = 0; + virtual void SetVisibility(bool visible) = 0; virtual bool GetVisibility() const = 0; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp index fc62690cc4..bdbf445b7f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp @@ -76,6 +76,13 @@ namespace AZ ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodOverride, "Lod Override", "Allows the rendered LOD to be overridden instead of being calculated automatically.") ->Attribute(AZ::Edit::Attributes::EnumValues, &MeshComponentConfig::GetLodOverrideValues) ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::IsAssetSet) + ->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_minimumScreenCoverage, "Minimum Screen Coverage", "Minimum proportion of screen area an entitiy takes up, after that the entitiy is culled.") + ->Attribute(AZ::Edit::Attributes::Min, 0.f) + ->Attribute(AZ::Edit::Attributes::Max, 1.f) + ->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_qualityDecayRate, "Quality Decay Rate", + "Rate at which mesh quality decays (0 -> always stay highest quality, 1 -> quality falls off to lowest quality immediately).") + ->Attribute(AZ::Edit::Attributes::Min, 0.f) + ->Attribute(AZ::Edit::Attributes::Max, 1.f) ->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_excludeFromReflectionCubeMaps, "Exclude from reflection cubemaps", "Mesh will not be visible in baked reflection probe cubemaps") ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_useForwardPassIblSpecular, "Use Forward Pass IBL Specular", diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 29bd9a839b..5fde185e4c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -40,6 +40,8 @@ namespace AZ ->Field("ModelAsset", &MeshComponentConfig::m_modelAsset) ->Field("SortKey", &MeshComponentConfig::m_sortKey) ->Field("LodOverride", &MeshComponentConfig::m_lodOverride) + ->Field("MinimumScreenCoverage", &MeshComponentConfig::m_minimumScreenCoverage) + ->Field("QualityDecayRate", &MeshComponentConfig::m_qualityDecayRate) ->Field("ExcludeFromReflectionCubeMaps", &MeshComponentConfig::m_excludeFromReflectionCubeMaps) ->Field("UseForwardPassIBLSpecular", &MeshComponentConfig::m_useForwardPassIblSpecular); } @@ -116,10 +118,16 @@ namespace AZ ->Event("GetSortKey", &MeshComponentRequestBus::Events::GetSortKey) ->Event("SetLodOverride", &MeshComponentRequestBus::Events::SetLodOverride) ->Event("GetLodOverride", &MeshComponentRequestBus::Events::GetLodOverride) + ->Event("SetMinimumScreenCoverage", &MeshComponentRequestBus::Events::SetMinimumScreenCoverage) + ->Event("GetMinimumScreenCoverage", &MeshComponentRequestBus::Events::GetMinimumScreenCoverage) + ->Event("SetQualityDecayRate", &MeshComponentRequestBus::Events::SetQualityDecayRate) + ->Event("GetQualityDecayRate", &MeshComponentRequestBus::Events::GetQualityDecayRate) ->VirtualProperty("ModelAssetId", "GetModelAssetId", "SetModelAssetId") ->VirtualProperty("ModelAssetPath", "GetModelAssetPath", "SetModelAssetPath") ->VirtualProperty("SortKey", "GetSortKey", "SetSortKey") ->VirtualProperty("LodOverride", "GetLodOverride", "SetLodOverride") + ->VirtualProperty("MinimumScreenCoverage", "GetMinimumScreenCoverage", "SetMinimumScreenCoverage") + ->VirtualProperty("QualityDecayRate", "GetQualityDecayRate", "SetQualityDecayRate") ; } } @@ -325,6 +333,8 @@ namespace AZ m_meshFeatureProcessor->SetTransform(m_meshHandle, transform, m_cachedNonUniformScale); m_meshFeatureProcessor->SetSortKey(m_meshHandle, m_configuration.m_sortKey); m_meshFeatureProcessor->SetLodOverride(m_meshHandle, m_configuration.m_lodOverride); + m_meshFeatureProcessor->SetMinimumScreenCoverage(m_meshHandle, m_configuration.m_minimumScreenCoverage); + m_meshFeatureProcessor->SetQualityDecayRate(m_meshHandle, m_configuration.m_qualityDecayRate); m_meshFeatureProcessor->SetExcludeFromReflectionCubeMaps(m_meshHandle, m_configuration.m_excludeFromReflectionCubeMaps); m_meshFeatureProcessor->SetVisible(m_meshHandle, m_isVisible); @@ -426,6 +436,28 @@ namespace AZ return m_meshFeatureProcessor->GetSortKey(m_meshHandle); } + void MeshComponentController::SetMinimumScreenCoverage(float minimumScreenCoverage) + { + m_configuration.m_minimumScreenCoverage = minimumScreenCoverage; + m_meshFeatureProcessor->SetMinimumScreenCoverage(m_meshHandle, minimumScreenCoverage); + } + + float MeshComponentController::GetMinimumScreenCoverage() const + { + return m_meshFeatureProcessor->GetMinimumScreenCoverage(m_meshHandle); + } + + void MeshComponentController::SetQualityDecayRate(float qualityDecayRate) + { + m_configuration.m_qualityDecayRate = qualityDecayRate; + m_meshFeatureProcessor->SetQualityDecayRate(m_meshHandle, qualityDecayRate); + } + + float MeshComponentController::GetQualityDecayRate() const + { + return m_meshFeatureProcessor->GetQualityDecayRate(m_meshHandle); + } + void MeshComponentController::SetVisibility(bool visible) { if (m_isVisible != visible) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h index 80b483452f..f94771b3e5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h @@ -46,6 +46,8 @@ namespace AZ Data::Asset m_modelAsset = { AZ::Data::AssetLoadBehavior::QueueLoad }; RHI::DrawItemSortKey m_sortKey = 0; RPI::Cullable::LodOverride m_lodOverride = RPI::Cullable::NoLodOverride; + float m_minimumScreenCoverage = 1.0f / 1080.0f; + float m_qualityDecayRate = 0.5f; bool m_excludeFromReflectionCubeMaps = false; bool m_useForwardPassIblSpecular = false; }; @@ -97,6 +99,11 @@ namespace AZ void SetLodOverride(RPI::Cullable::LodOverride lodOverride) override; RPI::Cullable::LodOverride GetLodOverride() const override; + void SetMinimumScreenCoverage(float minimumScreenCoverage) override; + float GetMinimumScreenCoverage() const override; + void SetQualityDecayRate(float qualityDecayRate) override; + float GetQualityDecayRate() const override; + void SetVisibility(bool visible) override; bool GetVisibility() const override; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 4c6045d7ce..63912aa8a6 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -415,6 +415,26 @@ namespace AZ return m_meshFeatureProcessor->GetLodOverride(*m_meshHandle); } + void AtomActorInstance::SetMinimumScreenCoverage(float minimumScreenCoverage) + { + m_meshFeatureProcessor->SetMinimumScreenCoverage(*m_meshHandle, minimumScreenCoverage); + } + + float AtomActorInstance::GetMinimumScreenCoverage() const + { + return m_meshFeatureProcessor->GetMinimumScreenCoverage(*m_meshHandle); + } + + void AtomActorInstance::SetQualityDecayRate(float qualityDecayRate) + { + m_meshFeatureProcessor->SetQualityDecayRate(*m_meshHandle, qualityDecayRate); + } + + float AtomActorInstance::GetQualityDecayRate() const + { + return m_meshFeatureProcessor->GetQualityDecayRate(*m_meshHandle); + } + void AtomActorInstance::SetVisibility(bool visible) { SetIsVisible(visible); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h index c854fed3c1..bd9afc668e 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h @@ -140,6 +140,10 @@ namespace AZ RHI::DrawItemSortKey GetSortKey() const override; void SetLodOverride(RPI::Cullable::LodOverride lodOverride) override; RPI::Cullable::LodOverride GetLodOverride() const override; + void SetMinimumScreenCoverage(float minimumScreenCoverage) override; + float GetMinimumScreenCoverage() const override; + void SetQualityDecayRate(float qualityDecayRate) override; + float GetQualityDecayRate() const override; void SetVisibility(bool visible) override; bool GetVisibility() const override; // GetWorldBounds/GetLocalBounds already overridden by BoundsRequestBus::Handler From 1a48118ece6816993409a08a90a0f2161b2229de Mon Sep 17 00:00:00 2001 From: Kyle B Date: Mon, 2 Aug 2021 14:01:38 -0700 Subject: [PATCH 02/26] Added comments and formatted as close to the original Signed-off-by: Kyle B --- .../Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h | 2 +- .../Atom/Feature/Mesh/MeshFeatureProcessorInterface.h | 7 ++++--- .../Common/Code/Source/Mesh/MeshFeatureProcessor.cpp | 4 +--- .../Code/Source/Mesh/EditorMeshComponent.cpp | 1 + .../Code/Source/Mesh/MeshComponentController.h | 1 + 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index 3cdff52ba7..e7e794c76e 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -63,7 +63,7 @@ namespace AZ void SetRayTracingData(); void SetSortKey(RHI::DrawItemSortKey sortKey); RHI::DrawItemSortKey GetSortKey(); - void SetLodOverride( RPI::Cullable::LodOverride lodOverride); + void SetLodOverride(RPI::Cullable::LodOverride lodOverride); RPI::Cullable::LodOverride GetLodOverride(); void SetMinimumScreenCoverage(float minimumScreenCoverage); float GetMinimumScreenCoverage(); diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h index b71b420625..dd64472161 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h @@ -98,13 +98,14 @@ namespace AZ virtual void SetLodOverride(const MeshHandle& meshHandle, RPI::Cullable::LodOverride lodOverride) = 0; //! Gets the LOD override for a given mesh handle. virtual RPI::Cullable::LodOverride GetLodOverride(const MeshHandle& meshHandle) = 0; - + //! Sets the minimum screen percentage for a given mesh handle. This property is the minimum screen percentage the object can take up before culled. virtual void SetMinimumScreenCoverage(const MeshHandle& meshHandle, float minimumScreenCoverage) = 0; + //! Gets the minimum screen percentage for a given mesh handle. virtual float GetMinimumScreenCoverage(const MeshHandle& meshHandle) = 0; - + //! Sets the quality decay rate. This property is the speed at which the quality of the mesh with degrade if you are linearly moving away. virtual void SetQualityDecayRate(const MeshHandle& meshHandle, float qualityDecayRate) = 0; + //! Gets the quality decay rate. virtual float GetQualityDecayRate(const MeshHandle& meshHandle) = 0; - //! Sets the option to exclude this mesh from baked reflection probe cubemaps virtual void SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps) = 0; //! Sets the option to exclude this mesh from raytracing diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index ce8ead9318..7d1d7ed851 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -1098,7 +1098,6 @@ namespace AZ cullData.m_drawListMask.reset(); const size_t lodCount = lodAssets.size(); - for (size_t lodIndex = 0; lodIndex < lodCount; ++lodIndex) { //initialize the lod @@ -1117,8 +1116,7 @@ namespace AZ if (lodIndex < lodAssets.size() - 1) { //first and middle lods: compute a stepdown value for the min - lod.m_screenCoverageMin = - AZStd::GetMax(lodData.m_qualityDecayRate * lod.m_screenCoverageMax, lodData.m_minimumScreenCoverage); + lod.m_screenCoverageMin = AZStd::GetMax(lodData.m_qualityDecayRate * lod.m_screenCoverageMax, lodData.m_minimumScreenCoverage); } else { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp index bdbf445b7f..d46017af16 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp @@ -79,6 +79,7 @@ namespace AZ ->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_minimumScreenCoverage, "Minimum Screen Coverage", "Minimum proportion of screen area an entitiy takes up, after that the entitiy is culled.") ->Attribute(AZ::Edit::Attributes::Min, 0.f) ->Attribute(AZ::Edit::Attributes::Max, 1.f) + ->Attribute(AZ::Edit::Attributes::Suffix, " percent") ->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_qualityDecayRate, "Quality Decay Rate", "Rate at which mesh quality decays (0 -> always stay highest quality, 1 -> quality falls off to lowest quality immediately).") ->Attribute(AZ::Edit::Attributes::Min, 0.f) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h index f94771b3e5..888d4bb154 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h @@ -101,6 +101,7 @@ namespace AZ void SetMinimumScreenCoverage(float minimumScreenCoverage) override; float GetMinimumScreenCoverage() const override; + void SetQualityDecayRate(float qualityDecayRate) override; float GetQualityDecayRate() const override; From 3db93a564d1a7b5e8c7b87eccb56ce6009a4dd47 Mon Sep 17 00:00:00 2001 From: Kyle B Date: Tue, 3 Aug 2021 18:28:55 -0700 Subject: [PATCH 03/26] Made formatting changes per pull comments, incuding adding comments, changing spacing, and changing the ui type of component fields Signed-off-by: Kyle B --- .../Include/Atom/Feature/Mesh/MeshFeatureProcessor.h | 8 ++++---- .../Common/Code/Source/Mesh/MeshFeatureProcessor.cpp | 12 ++++++------ Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h | 2 +- .../Code/Source/Mesh/EditorMeshComponent.cpp | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index e7e794c76e..08f2dde474 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -62,13 +62,13 @@ namespace AZ void BuildDrawPacketList(size_t modelLodIndex); void SetRayTracingData(); void SetSortKey(RHI::DrawItemSortKey sortKey); - RHI::DrawItemSortKey GetSortKey(); + RHI::DrawItemSortKey GetSortKey() const; void SetLodOverride(RPI::Cullable::LodOverride lodOverride); - RPI::Cullable::LodOverride GetLodOverride(); + RPI::Cullable::LodOverride GetLodOverride() const; void SetMinimumScreenCoverage(float minimumScreenCoverage); - float GetMinimumScreenCoverage(); + float GetMinimumScreenCoverage() const; void SetQualityDecayRate(float qualityDecayRate); - float GetQualityDecayRate(); + float GetQualityDecayRate() const; void UpdateDrawPackets(bool forceUpdate = false); void BuildCullable(); void UpdateCullBounds(const TransformServiceFeatureProcessor* transformService); diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 7d1d7ed851..286724b06a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -380,7 +380,7 @@ namespace AZ } } - void MeshFeatureProcessor::SetMinimumScreenCoverage( const MeshHandle& meshHandle, float minimumScreenCoverage) + void MeshFeatureProcessor::SetMinimumScreenCoverage(const MeshHandle& meshHandle, float minimumScreenCoverage) { if (meshHandle.IsValid()) { @@ -388,7 +388,7 @@ namespace AZ } } - float MeshFeatureProcessor::GetMinimumScreenCoverage(const MeshHandle& meshHandle) + float MeshFeatureProcessor::GetMinimumScreenCoverage(const MeshHandle& meshHandle) const { if (meshHandle.IsValid()) { @@ -1028,7 +1028,7 @@ namespace AZ } } - RHI::DrawItemSortKey MeshDataInstance::GetSortKey() + RHI::DrawItemSortKey MeshDataInstance::GetSortKey() const { return m_sortKey; } @@ -1038,7 +1038,7 @@ namespace AZ m_cullable.m_lodData.m_lodOverride = lodOverride; } - RPI::Cullable::LodOverride MeshDataInstance::GetLodOverride() + RPI::Cullable::LodOverride MeshDataInstance::GetLodOverride() const { return m_cullable.m_lodData.m_lodOverride; } @@ -1048,7 +1048,7 @@ namespace AZ m_cullable.m_lodData.m_minimumScreenCoverage = minimumScreenCoverage; } - float MeshDataInstance::GetMinimumScreenCoverage() + float MeshDataInstance::GetMinimumScreenCoverage() const { return m_cullable.m_lodData.m_minimumScreenCoverage; } @@ -1058,7 +1058,7 @@ namespace AZ m_cullable.m_lodData.m_qualityDecayRate = qualityDecayRate; } - float MeshDataInstance::GetQualityDecayRate() + float MeshDataInstance::GetQualityDecayRate() const { return m_cullable.m_lodData.m_qualityDecayRate; } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h index 30cf091735..4a39a21e0b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -89,7 +89,7 @@ namespace AZ float m_lodSelectionRadius = 1.0f; // the minimum possibe area a sphere enclosing a mesh projected onto the screen should have before it is culled. - float m_minimumScreenCoverage = 1.0f / 1080.0f; + float m_minimumScreenCoverage = 1.0f / 1080.0f; //For default, mesh should cover at least a screen pixel at 1080p to be drawn // The screen area decay between 0 and 1, i.e. closer to 1 -> lose quality immediately, closer to 0 -> never lose quality float m_qualityDecayRate = 0.5f; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp index d46017af16..3308767de9 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp @@ -76,11 +76,11 @@ namespace AZ ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodOverride, "Lod Override", "Allows the rendered LOD to be overridden instead of being calculated automatically.") ->Attribute(AZ::Edit::Attributes::EnumValues, &MeshComponentConfig::GetLodOverrideValues) ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::IsAssetSet) - ->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_minimumScreenCoverage, "Minimum Screen Coverage", "Minimum proportion of screen area an entitiy takes up, after that the entitiy is culled.") + ->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentConfig::m_minimumScreenCoverage, "Minimum Screen Coverage", "Minimum proportion of screen area an entitiy takes up, after that the entitiy is culled.") ->Attribute(AZ::Edit::Attributes::Min, 0.f) ->Attribute(AZ::Edit::Attributes::Max, 1.f) ->Attribute(AZ::Edit::Attributes::Suffix, " percent") - ->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_qualityDecayRate, "Quality Decay Rate", + ->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentConfig::m_qualityDecayRate, "Quality Decay Rate", "Rate at which mesh quality decays (0 -> always stay highest quality, 1 -> quality falls off to lowest quality immediately).") ->Attribute(AZ::Edit::Attributes::Min, 0.f) ->Attribute(AZ::Edit::Attributes::Max, 1.f) From 9c5c2e7de651c2d4c643ec2859ee763af5cc063b Mon Sep 17 00:00:00 2001 From: Kyle B Date: Tue, 3 Aug 2021 19:34:17 -0700 Subject: [PATCH 04/26] un-did const on function that did not need it Signed-off-by: Kyle B --- .../Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 286724b06a..166c5610b1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -388,7 +388,7 @@ namespace AZ } } - float MeshFeatureProcessor::GetMinimumScreenCoverage(const MeshHandle& meshHandle) const + float MeshFeatureProcessor::GetMinimumScreenCoverage(const MeshHandle& meshHandle) { if (meshHandle.IsValid()) { From baab204c0bf79a7932ad5ddbb57931e68c47802c Mon Sep 17 00:00:00 2001 From: Kyle B Date: Thu, 5 Aug 2021 00:07:54 -0700 Subject: [PATCH 05/26] updated Mock with new interface values Signed-off-by: Kyle B --- .../Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h index 72e547fc1b..0eea0df514 100644 --- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h @@ -32,9 +32,13 @@ namespace UnitTest MOCK_METHOD2(SetLocalAabb, void(const MeshHandle&, const AZ::Aabb&)); MOCK_CONST_METHOD1(GetLocalAabb, AZ::Aabb(const MeshHandle&)); MOCK_METHOD2(SetSortKey, void (const MeshHandle&, AZ::RHI::DrawItemSortKey)); - MOCK_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&)); + MOCK_CONST_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&)); MOCK_METHOD2(SetLodOverride, void(const MeshHandle&, AZ::RPI::Cullable::LodOverride)); - MOCK_METHOD1(GetLodOverride, AZ::RPI::Cullable::LodOverride(const MeshHandle&)); + MOCK_CONST_METHOD1(GetLodOverride, AZ::RPI::Cullable::LodOverride(const MeshHandle&)); + MOCK_METHOD2(SetMinimumScreenCoverage, void(const MeshHandle&, float)); + MOCK_CONST_METHOD1(GetMinimumScreenCoverage, float(const MeshHandle&)); + MOCK_METHOD2(SetQualityDecayRate, void(const MeshHandle&, float)); + MOCK_CONST_METHOD1(GetQualityDecayRate, float(const MeshHandle&)); MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Render::MaterialAssignmentMap&)); MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Data::Instance&)); MOCK_METHOD2(SetRayTracingEnabled, void (const MeshHandle&, bool)); From 51271fa15bec613f96c269d0cf1487e9ed524876 Mon Sep 17 00:00:00 2001 From: Kyle B Date: Fri, 6 Aug 2021 16:57:00 -0700 Subject: [PATCH 06/26] Created group for Lod component data Signed-off-by: Kyle B --- .../Atom/Feature/Mesh/MeshFeatureProcessor.h | 18 +--- .../Mesh/MeshFeatureProcessorInterface.h | 16 +--- .../Code/Mocks/MockMeshFeatureProcessor.h | 8 +- .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 86 +++---------------- .../Code/Include/Atom/RPI.Public/Culling.h | 16 +++- .../RPI/Code/Source/RPI.Public/Culling.cpp | 6 +- .../CommonFeatures/Mesh/MeshComponentBus.h | 3 + .../Code/Source/Mesh/EditorMeshComponent.cpp | 40 +++++---- .../Source/Mesh/MeshComponentController.cpp | 73 ++++++++++++---- .../Source/Mesh/MeshComponentController.h | 29 +++++-- .../Code/Source/AtomActorInstance.cpp | 30 +++++-- .../Code/Source/AtomActorInstance.h | 2 + 12 files changed, 167 insertions(+), 160 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index 08f2dde474..daf4a493c2 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -63,12 +63,8 @@ namespace AZ void SetRayTracingData(); void SetSortKey(RHI::DrawItemSortKey sortKey); RHI::DrawItemSortKey GetSortKey() const; - void SetLodOverride(RPI::Cullable::LodOverride lodOverride); - RPI::Cullable::LodOverride GetLodOverride() const; - void SetMinimumScreenCoverage(float minimumScreenCoverage); - float GetMinimumScreenCoverage() const; - void SetQualityDecayRate(float qualityDecayRate); - float GetQualityDecayRate() const; + void SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig); + RPI::Cullable::LodConfiguration GetMeshLodConfiguration() const; void UpdateDrawPackets(bool forceUpdate = false); void BuildCullable(); void UpdateCullBounds(const TransformServiceFeatureProcessor* transformService); @@ -159,14 +155,8 @@ namespace AZ void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) override; RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) override; - void SetLodOverride(const MeshHandle& meshHandle, RPI::Cullable::LodOverride lodOverride) override; - RPI::Cullable::LodOverride GetLodOverride(const MeshHandle& meshHandle) override; - - void SetMinimumScreenCoverage(const MeshHandle& meshHandle, float minimumScreenCoverage) override; - float GetMinimumScreenCoverage(const MeshHandle& meshHandle) override; - - void SetQualityDecayRate(const MeshHandle& meshHandle, float qualityDecayRate) override; - float GetQualityDecayRate(const MeshHandle& meshHandle) override; + void SetMeshLodConfiguration(const MeshHandle& meshHandle, RPI::Cullable::LodConfiguration meshLodConfig); + RPI::Cullable::LodConfiguration GetMeshLodConfiguration(const MeshHandle& meshHandle) const; void SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps) override; void SetRayTracingEnabled(const MeshHandle& meshHandle, bool rayTracingEnabled) override; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h index dd64472161..8c7a200ff5 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h @@ -94,18 +94,10 @@ namespace AZ virtual void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) = 0; //! Gets the sort key for a given mesh handle. virtual RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) = 0; - //! Sets an LOD override for a given mesh handle. This LOD will always be rendered instead being automatically determined. - virtual void SetLodOverride(const MeshHandle& meshHandle, RPI::Cullable::LodOverride lodOverride) = 0; - //! Gets the LOD override for a given mesh handle. - virtual RPI::Cullable::LodOverride GetLodOverride(const MeshHandle& meshHandle) = 0; - //! Sets the minimum screen percentage for a given mesh handle. This property is the minimum screen percentage the object can take up before culled. - virtual void SetMinimumScreenCoverage(const MeshHandle& meshHandle, float minimumScreenCoverage) = 0; - //! Gets the minimum screen percentage for a given mesh handle. - virtual float GetMinimumScreenCoverage(const MeshHandle& meshHandle) = 0; - //! Sets the quality decay rate. This property is the speed at which the quality of the mesh with degrade if you are linearly moving away. - virtual void SetQualityDecayRate(const MeshHandle& meshHandle, float qualityDecayRate) = 0; - //! Gets the quality decay rate. - virtual float GetQualityDecayRate(const MeshHandle& meshHandle) = 0; + //! Sets LOD mesh configurations to be used in the Mesh Feature Processor + virtual void SetMeshLodConfiguration(const MeshHandle& meshHandle, RPI::Cullable::LodConfiguration meshLodConfig) = 0; + //! Gets the LOD mesh configurations being used in the Mesh Feature Processor + virtual RPI::Cullable::LodConfiguration GetMeshLodConfiguration(const MeshHandle& meshHandle) const = 0; //! Sets the option to exclude this mesh from baked reflection probe cubemaps virtual void SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps) = 0; //! Sets the option to exclude this mesh from raytracing diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h index 0eea0df514..0c03e767e7 100644 --- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h @@ -33,12 +33,8 @@ namespace UnitTest MOCK_CONST_METHOD1(GetLocalAabb, AZ::Aabb(const MeshHandle&)); MOCK_METHOD2(SetSortKey, void (const MeshHandle&, AZ::RHI::DrawItemSortKey)); MOCK_CONST_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&)); - MOCK_METHOD2(SetLodOverride, void(const MeshHandle&, AZ::RPI::Cullable::LodOverride)); - MOCK_CONST_METHOD1(GetLodOverride, AZ::RPI::Cullable::LodOverride(const MeshHandle&)); - MOCK_METHOD2(SetMinimumScreenCoverage, void(const MeshHandle&, float)); - MOCK_CONST_METHOD1(GetMinimumScreenCoverage, float(const MeshHandle&)); - MOCK_METHOD2(SetQualityDecayRate, void(const MeshHandle&, float)); - MOCK_CONST_METHOD1(GetQualityDecayRate, float(const MeshHandle&)); + MOCK_METHOD2(SetMeshLodConfiguration, void(const MeshHandle&, RPI::Cullable::LodConfiguration)); + MOCK_CONST_METHOD1(GetMeshLodConfiguration, RPI::Cullable::LodConfiguration(const MeshHandle&)); MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Render::MaterialAssignmentMap&)); MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Data::Instance&)); MOCK_METHOD2(SetRayTracingEnabled, void (const MeshHandle&, bool)); diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 166c5610b1..679e64e283 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -359,66 +359,24 @@ namespace AZ } } - void MeshFeatureProcessor::SetLodOverride(const MeshHandle& meshHandle, RPI::Cullable::LodOverride lodOverride) + void MeshFeatureProcessor::SetMeshLodConfiguration(const MeshHandle& meshHandle, RPI::Cullable::LodConfiguration meshLodConfig) { if (meshHandle.IsValid()) { - meshHandle->SetLodOverride(lodOverride); + meshHandle->SetMeshLodConfiguration(meshLodConfig); } } - RPI::Cullable::LodOverride MeshFeatureProcessor::GetLodOverride(const MeshHandle& meshHandle) + RPI::Cullable::LodConfiguration MeshFeatureProcessor::GetMeshLodConfiguration(const MeshHandle& meshHandle) const { if (meshHandle.IsValid()) { - return meshHandle->GetLodOverride(); + return meshHandle->GetMeshLodConfiguration(); } else { AZ_Assert(false, "Invalid mesh handle"); - return 0; - } - } - - void MeshFeatureProcessor::SetMinimumScreenCoverage(const MeshHandle& meshHandle, float minimumScreenCoverage) - { - if (meshHandle.IsValid()) - { - meshHandle->SetMinimumScreenCoverage(minimumScreenCoverage); - } - } - - float MeshFeatureProcessor::GetMinimumScreenCoverage(const MeshHandle& meshHandle) - { - if (meshHandle.IsValid()) - { - return meshHandle->GetMinimumScreenCoverage(); - } - else - { - AZ_Assert(false, "Invalid mesh handle"); - return 0; - } - } - - void MeshFeatureProcessor::SetQualityDecayRate(const MeshHandle& meshHandle, float qualityDecayRate) - { - if (meshHandle.IsValid()) - { - meshHandle->SetQualityDecayRate(qualityDecayRate); - } - } - - float MeshFeatureProcessor::GetQualityDecayRate(const MeshHandle& meshHandle) - { - if (meshHandle.IsValid()) - { - return meshHandle->GetQualityDecayRate(); - } - else - { - AZ_Assert(false, "Invalid mesh handle"); - return 0; + return {0,0,0.0f,0.0f}; } } @@ -1033,34 +991,14 @@ namespace AZ return m_sortKey; } - void MeshDataInstance::SetLodOverride(RPI::Cullable::LodOverride lodOverride) + void MeshDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig) { - m_cullable.m_lodData.m_lodOverride = lodOverride; + m_cullable.m_lodData.m_lodConfiguration = meshLodConfig; } - RPI::Cullable::LodOverride MeshDataInstance::GetLodOverride() const + RPI::Cullable::LodConfiguration MeshDataInstance::GetMeshLodConfiguration() const { - return m_cullable.m_lodData.m_lodOverride; - } - - void MeshDataInstance::SetMinimumScreenCoverage(float minimumScreenCoverage) - { - m_cullable.m_lodData.m_minimumScreenCoverage = minimumScreenCoverage; - } - - float MeshDataInstance::GetMinimumScreenCoverage() const - { - return m_cullable.m_lodData.m_minimumScreenCoverage; - } - - void MeshDataInstance::SetQualityDecayRate(float qualityDecayRate) - { - m_cullable.m_lodData.m_qualityDecayRate = qualityDecayRate; - } - - float MeshDataInstance::GetQualityDecayRate() const - { - return m_cullable.m_lodData.m_qualityDecayRate; + return m_cullable.m_lodData.m_lodConfiguration; } void MeshDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/) @@ -1110,18 +1048,18 @@ namespace AZ else { //every other lod: use the previous lod's min - lod.m_screenCoverageMax = AZStd::GetMax(lodData.m_lods[lodIndex - 1].m_screenCoverageMin, lodData.m_minimumScreenCoverage); + lod.m_screenCoverageMax = AZStd::GetMax(lodData.m_lods[lodIndex - 1].m_screenCoverageMin, lodData.m_lodConfiguration.m_minimumScreenCoverage); } if (lodIndex < lodAssets.size() - 1) { //first and middle lods: compute a stepdown value for the min - lod.m_screenCoverageMin = AZStd::GetMax(lodData.m_qualityDecayRate * lod.m_screenCoverageMax, lodData.m_minimumScreenCoverage); + lod.m_screenCoverageMin = AZStd::GetMax(lodData.m_lodConfiguration.m_qualityDecayRate * lod.m_screenCoverageMax, lodData.m_lodConfiguration.m_minimumScreenCoverage); } else { //last lod: use MinimumScreenCoverage for the min - lod.m_screenCoverageMin = lodData.m_minimumScreenCoverage; + lod.m_screenCoverageMin = lodData.m_lodConfiguration.m_minimumScreenCoverage; } lod.m_drawPackets.clear(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h index 4a39a21e0b..e89e180540 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -70,8 +70,18 @@ namespace AZ }; CullData m_cullData; + using LodType = uint8_t; using LodOverride = uint8_t; static constexpr uint8_t NoLodOverride = AZStd::numeric_limits::max(); + static constexpr uint8_t DefaultLodType = AZStd::numeric_limits::max(); + + struct LodConfiguration + { + LodType m_lodType; + LodOverride m_lodOverride; + float m_minimumScreenCoverage; + float m_qualityDecayRate; + }; struct LodData { @@ -89,11 +99,11 @@ namespace AZ float m_lodSelectionRadius = 1.0f; // the minimum possibe area a sphere enclosing a mesh projected onto the screen should have before it is culled. - float m_minimumScreenCoverage = 1.0f / 1080.0f; //For default, mesh should cover at least a screen pixel at 1080p to be drawn + static constexpr float DefaultMinimumScreenCoverage = 1.0f / 1080.0f; //For default, mesh should cover at least a screen pixel at 1080p to be drawn // The screen area decay between 0 and 1, i.e. closer to 1 -> lose quality immediately, closer to 0 -> never lose quality - float m_qualityDecayRate = 0.5f; + static constexpr float DefaultQualityDecayRate = 0.5f; - LodOverride m_lodOverride = NoLodOverride; + LodConfiguration m_lodConfiguration = { DefaultLodType, NoLodOverride, DefaultMinimumScreenCoverage, DefaultQualityDecayRate }; }; LodData m_lodData; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index e192e71fc4..f22d5c7224 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -672,7 +672,7 @@ namespace AZ } }; - if (lodData.m_lodOverride == Cullable::NoLodOverride) + if (lodData.m_lodConfiguration.m_lodOverride == Cullable::NoLodOverride) { for (const Cullable::LodData::Lod& lod : lodData.m_lods) { @@ -683,9 +683,9 @@ namespace AZ } } } - else if(lodData.m_lodOverride < lodData.m_lods.size()) + else if(lodData.m_lodConfiguration.m_lodOverride < lodData.m_lods.size()) { - addLodToDrawPacket(lodData.m_lods.at(lodData.m_lodOverride)); + addLodToDrawPacket(lodData.m_lods.at(lodData.m_lodConfiguration.m_lodOverride)); } return numVisibleDrawPackets; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h index baef507b7a..cc9c78d356 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h @@ -36,6 +36,9 @@ namespace AZ virtual void SetSortKey(RHI::DrawItemSortKey sortKey) = 0; virtual RHI::DrawItemSortKey GetSortKey() const = 0; + virtual void SetLodType(RPI::Cullable::LodType lodType) = 0; + virtual RPI::Cullable::LodType GetLodType() const = 0; + virtual void SetLodOverride(RPI::Cullable::LodOverride lodOverride) = 0; virtual RPI::Cullable::LodOverride GetLodOverride() const = 0; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp index 3308767de9..0719d9f2bb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp @@ -71,24 +71,28 @@ namespace AZ "MeshComponentConfig", "") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_modelAsset, "Mesh Asset", "Mesh asset reference") - ->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_sortKey, "Sort Key", "Transparent meshes are drawn by sort key then depth. Used this to force certain transparent meshes to draw before or after others.") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodOverride, "Lod Override", "Allows the rendered LOD to be overridden instead of being calculated automatically.") - ->Attribute(AZ::Edit::Attributes::EnumValues, &MeshComponentConfig::GetLodOverrideValues) - ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::IsAssetSet) - ->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentConfig::m_minimumScreenCoverage, "Minimum Screen Coverage", "Minimum proportion of screen area an entitiy takes up, after that the entitiy is culled.") - ->Attribute(AZ::Edit::Attributes::Min, 0.f) - ->Attribute(AZ::Edit::Attributes::Max, 1.f) - ->Attribute(AZ::Edit::Attributes::Suffix, " percent") - ->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentConfig::m_qualityDecayRate, "Quality Decay Rate", - "Rate at which mesh quality decays (0 -> always stay highest quality, 1 -> quality falls off to lowest quality immediately).") - ->Attribute(AZ::Edit::Attributes::Min, 0.f) - ->Attribute(AZ::Edit::Attributes::Max, 1.f) - ->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_excludeFromReflectionCubeMaps, "Exclude from reflection cubemaps", "Mesh will not be visible in baked reflection probe cubemaps") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_useForwardPassIblSpecular, "Use Forward Pass IBL Specular", - "Renders IBL specular reflections in the forward pass, using only the most influential probe (based on the position of the entity) and the global IBL cubemap. Can reduce rendering costs, but only recommended for static objects that are affected by at most one reflection probe.") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_modelAsset, "Mesh Asset", "Mesh asset reference") + ->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_sortKey, "Sort Key", "Transparent meshes are drawn by sort key then depth. Used this to force certain transparent meshes to draw before or after others.") + ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::IsAssetSet) + ->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_excludeFromReflectionCubeMaps, "Exclude from reflection cubemaps", "Mesh will not be visible in baked reflection probe cubemaps") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_useForwardPassIblSpecular, "Use Forward Pass IBL Specular", + "Renders IBL specular reflections in the forward pass, using only the most influential probe (based on the position of the entity) and the global IBL cubemap. Can reduce rendering costs, but only recommended for static objects that are affected by at most one reflection probe.") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->ClassElement(AZ::Edit::ClassElements::Group, "Lod Configuration") + ->Attribute(AZ::Edit::Attributes::AutoExpand, false) + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodType, "Lod Type", "Lod Method.") + ->Attribute(AZ::Edit::Attributes::EnumValues, &MeshComponentConfig::GetLodTypeValues) + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodOverride, "Lod Override", "Allows the rendered LOD to be overridden instead of being calculated automatically.") + ->Attribute(AZ::Edit::Attributes::EnumValues, &MeshComponentConfig::GetLodOverrideValues) + ->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentConfig::m_minimumScreenCoverage, "Minimum Screen Coverage", "Minimum proportion of screen area an entitiy takes up, after that the entitiy is culled.") + ->Attribute(AZ::Edit::Attributes::Min, 0.f) + ->Attribute(AZ::Edit::Attributes::Max, 1.f) + ->Attribute(AZ::Edit::Attributes::Suffix, " percent") + ->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentConfig::m_qualityDecayRate, "Quality Decay Rate", + "Rate at which mesh quality decays (0 -> always stay highest quality, 1 -> quality falls off to lowest quality immediately).") + ->Attribute(AZ::Edit::Attributes::Min, 0.f) + ->Attribute(AZ::Edit::Attributes::Max, 1.f) ; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 5fde185e4c..adcf570899 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -39,11 +39,12 @@ namespace AZ ->Version(1) ->Field("ModelAsset", &MeshComponentConfig::m_modelAsset) ->Field("SortKey", &MeshComponentConfig::m_sortKey) + ->Field("ExcludeFromReflectionCubeMaps", &MeshComponentConfig::m_excludeFromReflectionCubeMaps) + ->Field("UseForwardPassIBLSpecular", &MeshComponentConfig::m_useForwardPassIblSpecular) + ->Field("LodType", &MeshComponentConfig::m_lodType) ->Field("LodOverride", &MeshComponentConfig::m_lodOverride) ->Field("MinimumScreenCoverage", &MeshComponentConfig::m_minimumScreenCoverage) - ->Field("QualityDecayRate", &MeshComponentConfig::m_qualityDecayRate) - ->Field("ExcludeFromReflectionCubeMaps", &MeshComponentConfig::m_excludeFromReflectionCubeMaps) - ->Field("UseForwardPassIBLSpecular", &MeshComponentConfig::m_useForwardPassIblSpecular); + ->Field("QualityDecayRate", &MeshComponentConfig::m_qualityDecayRate); } } @@ -85,6 +86,13 @@ namespace AZ return values; } + AZStd::vector> MeshComponentConfig::GetLodTypeValues() + { + return { + {RPI::Cullable::DefaultLodType, "Default"} + }; + } + MeshComponentController::~MeshComponentController() { // Release memory, disconnect from buses in the right order and broadcast events so that other components are aware. @@ -109,6 +117,11 @@ namespace AZ ->Attribute(AZ::Script::Attributes::Category, "render") ->Attribute(AZ::Script::Attributes::Module, "render"); + behaviorContext->ConstantProperty("DefaultLodType", BehaviorConstant(RPI::Cullable::DefaultLodType)) + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "render") + ->Attribute(AZ::Script::Attributes::Module, "render"); + behaviorContext->EBus("RenderMeshComponentRequestBus") ->Event("GetModelAssetId", &MeshComponentRequestBus::Events::GetModelAssetId) ->Event("SetModelAssetId", &MeshComponentRequestBus::Events::SetModelAssetId) @@ -116,6 +129,8 @@ namespace AZ ->Event("SetModelAssetPath", &MeshComponentRequestBus::Events::SetModelAssetPath) ->Event("SetSortKey", &MeshComponentRequestBus::Events::SetSortKey) ->Event("GetSortKey", &MeshComponentRequestBus::Events::GetSortKey) + ->Event("SetLodType", &MeshComponentRequestBus::Events::SetLodType) + ->Event("GetLodType", &MeshComponentRequestBus::Events::GetLodType) ->Event("SetLodOverride", &MeshComponentRequestBus::Events::SetLodOverride) ->Event("GetLodOverride", &MeshComponentRequestBus::Events::GetLodOverride) ->Event("SetMinimumScreenCoverage", &MeshComponentRequestBus::Events::SetMinimumScreenCoverage) @@ -125,6 +140,7 @@ namespace AZ ->VirtualProperty("ModelAssetId", "GetModelAssetId", "SetModelAssetId") ->VirtualProperty("ModelAssetPath", "GetModelAssetPath", "SetModelAssetPath") ->VirtualProperty("SortKey", "GetSortKey", "SetSortKey") + ->VirtualProperty("LodType", "GetLodType", "SetLodType") ->VirtualProperty("LodOverride", "GetLodOverride", "SetLodOverride") ->VirtualProperty("MinimumScreenCoverage", "GetMinimumScreenCoverage", "SetMinimumScreenCoverage") ->VirtualProperty("QualityDecayRate", "GetQualityDecayRate", "SetQualityDecayRate") @@ -332,9 +348,7 @@ namespace AZ m_meshFeatureProcessor->SetTransform(m_meshHandle, transform, m_cachedNonUniformScale); m_meshFeatureProcessor->SetSortKey(m_meshHandle, m_configuration.m_sortKey); - m_meshFeatureProcessor->SetLodOverride(m_meshHandle, m_configuration.m_lodOverride); - m_meshFeatureProcessor->SetMinimumScreenCoverage(m_meshHandle, m_configuration.m_minimumScreenCoverage); - m_meshFeatureProcessor->SetQualityDecayRate(m_meshHandle, m_configuration.m_qualityDecayRate); + m_meshFeatureProcessor->SetMeshLodConfiguration(m_meshHandle, GetMeshLodConfiguration()); m_meshFeatureProcessor->SetExcludeFromReflectionCubeMaps(m_meshHandle, m_configuration.m_excludeFromReflectionCubeMaps); m_meshFeatureProcessor->SetVisible(m_meshHandle, m_isVisible); @@ -425,37 +439,66 @@ namespace AZ return m_meshFeatureProcessor->GetSortKey(m_meshHandle); } + RPI::Cullable::LodConfiguration MeshComponentController::GetMeshLodConfiguration() const + { + return { + m_configuration.m_lodType, + m_configuration.m_lodOverride, + m_configuration.m_minimumScreenCoverage, + m_configuration.m_qualityDecayRate + }; + } + // ----------------------- + void MeshComponentController::SetLodType(RPI::Cullable::LodType lodType) + { + RPI::Cullable::LodConfiguration lodConfig = GetMeshLodConfiguration(); + lodConfig.m_lodType = lodType; + m_meshFeatureProcessor->SetMeshLodConfiguration(m_meshHandle, lodConfig); + } + + RPI::Cullable::LodType MeshComponentController::GetLodType() const + { + RPI::Cullable::LodConfiguration lodConfig = m_meshFeatureProcessor->GetMeshLodConfiguration(m_meshHandle); + return lodConfig.m_lodType; + } + void MeshComponentController::SetLodOverride(RPI::Cullable::LodOverride lodOverride) { - m_configuration.m_lodOverride = lodOverride; // Save for serialization - m_meshFeatureProcessor->SetLodOverride(m_meshHandle, lodOverride); + RPI::Cullable::LodConfiguration lodConfig = GetMeshLodConfiguration(); + lodConfig.m_lodOverride = lodOverride; + m_meshFeatureProcessor->SetMeshLodConfiguration(m_meshHandle, lodConfig); } RPI::Cullable::LodOverride MeshComponentController::GetLodOverride() const { - return m_meshFeatureProcessor->GetSortKey(m_meshHandle); + RPI::Cullable::LodConfiguration lodConfig = m_meshFeatureProcessor->GetMeshLodConfiguration(m_meshHandle); + return lodConfig.m_lodOverride; } void MeshComponentController::SetMinimumScreenCoverage(float minimumScreenCoverage) { - m_configuration.m_minimumScreenCoverage = minimumScreenCoverage; - m_meshFeatureProcessor->SetMinimumScreenCoverage(m_meshHandle, minimumScreenCoverage); + RPI::Cullable::LodConfiguration lodConfig = GetMeshLodConfiguration(); + lodConfig.m_minimumScreenCoverage = minimumScreenCoverage; + m_meshFeatureProcessor->SetMeshLodConfiguration(m_meshHandle, lodConfig); } float MeshComponentController::GetMinimumScreenCoverage() const { - return m_meshFeatureProcessor->GetMinimumScreenCoverage(m_meshHandle); + RPI::Cullable::LodConfiguration lodConfig = m_meshFeatureProcessor->GetMeshLodConfiguration(m_meshHandle); + return lodConfig.m_minimumScreenCoverage; } void MeshComponentController::SetQualityDecayRate(float qualityDecayRate) { - m_configuration.m_qualityDecayRate = qualityDecayRate; - m_meshFeatureProcessor->SetQualityDecayRate(m_meshHandle, qualityDecayRate); + RPI::Cullable::LodConfiguration lodConfig = GetMeshLodConfiguration(); + lodConfig.m_qualityDecayRate = qualityDecayRate; + m_meshFeatureProcessor->SetMeshLodConfiguration(m_meshHandle, lodConfig); } float MeshComponentController::GetQualityDecayRate() const { - return m_meshFeatureProcessor->GetQualityDecayRate(m_meshHandle); + RPI::Cullable::LodConfiguration lodConfig = m_meshFeatureProcessor->GetMeshLodConfiguration(m_meshHandle); + return lodConfig.m_qualityDecayRate; } void MeshComponentController::SetVisibility(bool visible) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h index 888d4bb154..1b479ed3eb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h @@ -30,6 +30,9 @@ namespace AZ { namespace Render { + + + //! A configuration structure for the MeshComponentController class MeshComponentConfig final : public AZ::ComponentConfig @@ -42,14 +45,17 @@ namespace AZ // Editor helper functions bool IsAssetSet(); AZStd::vector> GetLodOverrideValues(); + AZStd::vector> GetLodTypeValues(); Data::Asset m_modelAsset = { AZ::Data::AssetLoadBehavior::QueueLoad }; RHI::DrawItemSortKey m_sortKey = 0; - RPI::Cullable::LodOverride m_lodOverride = RPI::Cullable::NoLodOverride; - float m_minimumScreenCoverage = 1.0f / 1080.0f; - float m_qualityDecayRate = 0.5f; bool m_excludeFromReflectionCubeMaps = false; bool m_useForwardPassIblSpecular = false; + + RPI::Cullable::LodType m_lodType = RPI::Cullable::DefaultLodType; + RPI::Cullable::LodOverride m_lodOverride = RPI::Cullable::NoLodOverride; + float m_minimumScreenCoverage = RPI::Cullable::LodData::DefaultMinimumScreenCoverage; + float m_qualityDecayRate = RPI::Cullable::LodData::DefaultQualityDecayRate; }; class MeshComponentController final @@ -96,14 +102,17 @@ namespace AZ void SetSortKey(RHI::DrawItemSortKey sortKey) override; RHI::DrawItemSortKey GetSortKey() const override; - void SetLodOverride(RPI::Cullable::LodOverride lodOverride) override; - RPI::Cullable::LodOverride GetLodOverride() const override; + void SetLodType(RPI::Cullable::LodType lodType) override; + RPI::Cullable::LodType GetLodType() const override; - void SetMinimumScreenCoverage(float minimumScreenCoverage) override; - float GetMinimumScreenCoverage() const override; + virtual void SetLodOverride(RPI::Cullable::LodOverride lodOverride); + virtual RPI::Cullable::LodOverride GetLodOverride() const; - void SetQualityDecayRate(float qualityDecayRate) override; - float GetQualityDecayRate() const override; + virtual void SetMinimumScreenCoverage(float minimumScreenCoverage); + virtual float GetMinimumScreenCoverage() const; + + virtual void SetQualityDecayRate(float qualityDecayRate); + virtual float GetQualityDecayRate() const; void SetVisibility(bool visible) override; bool GetVisibility() const override; @@ -137,6 +146,8 @@ namespace AZ void UnregisterModel(); void RefreshModelRegistration(); + RPI::Cullable::LodConfiguration MeshComponentController::GetMeshLodConfiguration() const; + void HandleNonUniformScaleChange(const AZ::Vector3& nonUniformScale); Render::MeshFeatureProcessorInterface* m_meshFeatureProcessor = nullptr; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 63912aa8a6..e2debacb83 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -404,35 +404,53 @@ namespace AZ { return m_meshFeatureProcessor->GetSortKey(*m_meshHandle); } + + void AtomActorInstance::SetLodType(RPI::Cullable::LodType lodType) + { + RPI::Cullable::LodConfiguration config = m_meshFeatureProcessor->GetMeshLodConfiguration(*m_meshHandle); + config.m_lodType = lodType; + m_meshFeatureProcessor->SetMeshLodConfiguration(*m_meshHandle, config); + } + + RPI::Cullable::LodType AtomActorInstance::GetLodType() const + { + return m_meshFeatureProcessor->GetMeshLodConfiguration(*m_meshHandle).m_lodType; + } void AtomActorInstance::SetLodOverride(RPI::Cullable::LodOverride lodOverride) { - m_meshFeatureProcessor->SetLodOverride(*m_meshHandle, lodOverride); + RPI::Cullable::LodConfiguration config = m_meshFeatureProcessor->GetMeshLodConfiguration(*m_meshHandle); + config.m_lodOverride = lodOverride; + m_meshFeatureProcessor->SetMeshLodConfiguration(*m_meshHandle, config); } RPI::Cullable::LodOverride AtomActorInstance::GetLodOverride() const { - return m_meshFeatureProcessor->GetLodOverride(*m_meshHandle); + return m_meshFeatureProcessor->GetMeshLodConfiguration(*m_meshHandle).m_lodOverride; } void AtomActorInstance::SetMinimumScreenCoverage(float minimumScreenCoverage) { - m_meshFeatureProcessor->SetMinimumScreenCoverage(*m_meshHandle, minimumScreenCoverage); + RPI::Cullable::LodConfiguration config = m_meshFeatureProcessor->GetMeshLodConfiguration(*m_meshHandle); + config.m_minimumScreenCoverage = minimumScreenCoverage; + m_meshFeatureProcessor->SetMeshLodConfiguration(*m_meshHandle, config); } float AtomActorInstance::GetMinimumScreenCoverage() const { - return m_meshFeatureProcessor->GetMinimumScreenCoverage(*m_meshHandle); + return m_meshFeatureProcessor->GetMeshLodConfiguration(*m_meshHandle).m_minimumScreenCoverage; } void AtomActorInstance::SetQualityDecayRate(float qualityDecayRate) { - m_meshFeatureProcessor->SetQualityDecayRate(*m_meshHandle, qualityDecayRate); + RPI::Cullable::LodConfiguration config = m_meshFeatureProcessor->GetMeshLodConfiguration(*m_meshHandle); + config.m_qualityDecayRate = qualityDecayRate; + m_meshFeatureProcessor->SetMeshLodConfiguration(*m_meshHandle, config); } float AtomActorInstance::GetQualityDecayRate() const { - return m_meshFeatureProcessor->GetQualityDecayRate(*m_meshHandle); + return m_meshFeatureProcessor->GetMeshLodConfiguration(*m_meshHandle).m_qualityDecayRate; } void AtomActorInstance::SetVisibility(bool visible) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h index bd9afc668e..bf832e9def 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h @@ -138,6 +138,8 @@ namespace AZ AZ::Data::Instance GetModel() const override; void SetSortKey(RHI::DrawItemSortKey sortKey) override; RHI::DrawItemSortKey GetSortKey() const override; + void SetLodType(RPI::Cullable::LodType lodType) override; + RPI::Cullable::LodType GetLodType() const override; void SetLodOverride(RPI::Cullable::LodOverride lodOverride) override; RPI::Cullable::LodOverride GetLodOverride() const override; void SetMinimumScreenCoverage(float minimumScreenCoverage) override; From 0c05c9f20462a708de228e5ff06acd96d9b3a533 Mon Sep 17 00:00:00 2001 From: Kyle B Date: Wed, 11 Aug 2021 15:49:50 -0700 Subject: [PATCH 07/26] [not working] Made lod selection more generic for further work Signed-off-by: Kyle B --- .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 2 +- .../Code/Include/Atom/RPI.Public/Culling.h | 26 +++++------ .../RPI/Code/Source/RPI.Public/Culling.cpp | 27 ++++++----- .../QuadSphere_Default.material | 28 +++++++++++ .../Code/Source/Mesh/EditorMeshComponent.cpp | 9 +++- .../Source/Mesh/MeshComponentController.cpp | 46 +++++++++++++++++-- .../Source/Mesh/MeshComponentController.h | 11 +++-- 7 files changed, 113 insertions(+), 36 deletions(-) create mode 100644 Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/QuadSphere_Default.material diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 679e64e283..363723f7da 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -376,7 +376,7 @@ namespace AZ else { AZ_Assert(false, "Invalid mesh handle"); - return {0,0,0.0f,0.0f}; + return {RPI::Cullable::LodType::Default, 0, 0.0f, 0.0f }; } } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h index e89e180540..82e9c733c8 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -70,17 +70,22 @@ namespace AZ }; CullData m_cullData; - using LodType = uint8_t; + enum LodType : uint8_t + { + Default = 0, + ScreenCoverage, + SpecificLod, + }; using LodOverride = uint8_t; - static constexpr uint8_t NoLodOverride = AZStd::numeric_limits::max(); - static constexpr uint8_t DefaultLodType = AZStd::numeric_limits::max(); struct LodConfiguration { - LodType m_lodType; - LodOverride m_lodOverride; - float m_minimumScreenCoverage; - float m_qualityDecayRate; + LodType m_lodType = LodType::Default; + LodOverride m_lodOverride = 0; + // the minimum possibe area a sphere enclosing a mesh projected onto the screen should have before it is culled. + float m_minimumScreenCoverage = 1.0f / 1080.0f; // For default, mesh should cover at least a screen pixel at 1080p to be drawn; + // The screen area decay between 0 and 1, i.e. closer to 1 -> lose quality immediately, closer to 0 -> never lose quality + float m_qualityDecayRate = 0.5f; }; struct LodData @@ -98,12 +103,7 @@ namespace AZ //! Suggest setting to: 0.5f*localAabb.GetExtents().GetMaxElement() float m_lodSelectionRadius = 1.0f; - // the minimum possibe area a sphere enclosing a mesh projected onto the screen should have before it is culled. - static constexpr float DefaultMinimumScreenCoverage = 1.0f / 1080.0f; //For default, mesh should cover at least a screen pixel at 1080p to be drawn - // The screen area decay between 0 and 1, i.e. closer to 1 -> lose quality immediately, closer to 0 -> never lose quality - static constexpr float DefaultQualityDecayRate = 0.5f; - - LodConfiguration m_lodConfiguration = { DefaultLodType, NoLodOverride, DefaultMinimumScreenCoverage, DefaultQualityDecayRate }; + LodConfiguration m_lodConfiguration; }; LodData m_lodData; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index f22d5c7224..c0d9023fa9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -672,20 +672,25 @@ namespace AZ } }; - if (lodData.m_lodConfiguration.m_lodOverride == Cullable::NoLodOverride) + switch (lodData.m_lodConfiguration.m_lodType) { - for (const Cullable::LodData::Lod& lod : lodData.m_lods) - { - //Note that this supports overlapping lod ranges (to suport cross-fading lods, for example) - if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax) + case Cullable::LodType::SpecificLod: + if (lodData.m_lodConfiguration.m_lodOverride < lodData.m_lods.size()) { - addLodToDrawPacket(lod); + addLodToDrawPacket(lodData.m_lods.at(lodData.m_lodConfiguration.m_lodOverride)); } - } - } - else if(lodData.m_lodConfiguration.m_lodOverride < lodData.m_lods.size()) - { - addLodToDrawPacket(lodData.m_lods.at(lodData.m_lodConfiguration.m_lodOverride)); + break; + case Cullable::LodType::ScreenCoverage: + default: + for (const Cullable::LodData::Lod& lod : lodData.m_lods) + { + // Note that this supports overlapping lod ranges (to suport cross-fading lods, for example) + if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax) + { + addLodToDrawPacket(lod); + } + } + break; } return numVisibleDrawPackets; diff --git a/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/QuadSphere_Default.material b/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/QuadSphere_Default.material new file mode 100644 index 0000000000..4905c302fe --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/QuadSphere_Default.material @@ -0,0 +1,28 @@ +{ + "description": "", + "materialType": "Materials/Types/StandardPBR.materialtype", + "parentMaterial": "", + "propertyLayoutVersion": 3, + "properties": { + "baseColor": { + "color": [ + 0.800000011920929, + 0.800000011920929, + 0.800000011920929, + 1.0 + ], + "textureMap": "MaterialEditor/ViewportModels/_dev_shaderball_00_basecolor.png" + }, + "emissive": { + "color": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "opacity": { + "factor": 1.0 + } + } +} \ No newline at end of file diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp index 0719d9f2bb..ff0741fc31 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp @@ -79,20 +79,25 @@ namespace AZ ->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_useForwardPassIblSpecular, "Use Forward Pass IBL Specular", "Renders IBL specular reflections in the forward pass, using only the most influential probe (based on the position of the entity) and the global IBL cubemap. Can reduce rendering costs, but only recommended for static objects that are affected by at most one reflection probe.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->ClassElement(AZ::Edit::ClassElements::Group, "Lod Configuration") - ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodType, "Lod Type", "Lod Method.") ->Attribute(AZ::Edit::Attributes::EnumValues, &MeshComponentConfig::GetLodTypeValues) + ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::IsAssetSet) + ->ClassElement(AZ::Edit::ClassElements::Group, "Lod Configuration") + ->Attribute(AZ::Edit::Attributes::AutoExpand, false) + ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::ShowLodConfig) ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodOverride, "Lod Override", "Allows the rendered LOD to be overridden instead of being calculated automatically.") ->Attribute(AZ::Edit::Attributes::EnumValues, &MeshComponentConfig::GetLodOverrideValues) + ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::LodTypeIsSpecificLOD) ->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentConfig::m_minimumScreenCoverage, "Minimum Screen Coverage", "Minimum proportion of screen area an entitiy takes up, after that the entitiy is culled.") ->Attribute(AZ::Edit::Attributes::Min, 0.f) ->Attribute(AZ::Edit::Attributes::Max, 1.f) ->Attribute(AZ::Edit::Attributes::Suffix, " percent") + ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::LodTypeIsScreenCoverage) ->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentConfig::m_qualityDecayRate, "Quality Decay Rate", "Rate at which mesh quality decays (0 -> always stay highest quality, 1 -> quality falls off to lowest quality immediately).") ->Attribute(AZ::Edit::Attributes::Min, 0.f) ->Attribute(AZ::Edit::Attributes::Max, 1.f) + ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::LodTypeIsScreenCoverage) ; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index adcf570899..3d049d0f97 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -31,11 +31,30 @@ namespace AZ { namespace Render { + + namespace MeshComponentControllerVersionUtility + { + bool VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) + { + if (classElement.GetVersion() < 2) + { + RPI::Cullable::LodOverride lodOverride = classElement.FindElement(AZ_CRC("LodOverride")); + static constexpr uint8_t old_NoLodOverride = AZStd::numeric_limits ::max(); + if (lodOverride == old_NoLodOverride) + { + classElement.AddElementWithData(context, "LodType", RPI::Cullable::LodType::SpecificLod); + } + } + return true; + } + } // namespace MeshComponentControllerVersionUtility + void MeshComponentConfig::Reflect(ReflectContext* context) { if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() + //->Version(2, &MeshComponentControllerVersionUtility::VersionConverter) ->Version(1) ->Field("ModelAsset", &MeshComponentConfig::m_modelAsset) ->Field("SortKey", &MeshComponentConfig::m_sortKey) @@ -53,6 +72,21 @@ namespace AZ return m_modelAsset.GetId().IsValid(); } + bool MeshComponentConfig::LodTypeIsScreenCoverage() + { + return m_lodType == RPI::Cullable::LodType::ScreenCoverage; + } + + bool MeshComponentConfig::LodTypeIsSpecificLOD() + { + return m_lodType == RPI::Cullable::LodType::SpecificLod; + } + + bool MeshComponentConfig::ShowLodConfig() + { + return LodTypeIsScreenCoverage() && LodTypeIsSpecificLOD(); + } + AZStd::vector> MeshComponentConfig::GetLodOverrideValues() { AZStd::vector> values; @@ -75,9 +109,9 @@ namespace AZ } values.reserve(lodCount + 1); - values.push_back({ RPI::Cullable::NoLodOverride, "Not Set" }); + values.push_back({0, "Default (Highest)" }); - for (uint32_t i = 0; i < lodCount; ++i) + for (uint32_t i = 1; i < lodCount; ++i) { AZStd::string enumDescription = AZStd::string::format("Lod %i", i); values.push_back({ aznumeric_cast(i), enumDescription.c_str() }); @@ -89,7 +123,9 @@ namespace AZ AZStd::vector> MeshComponentConfig::GetLodTypeValues() { return { - {RPI::Cullable::DefaultLodType, "Default"} + {aznumeric_cast(0), "Default"}, + {aznumeric_cast(1), "Screen Coverage" }, + {aznumeric_cast(2), "Specific Lod" } }; } @@ -112,12 +148,12 @@ namespace AZ if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->ConstantProperty("NoLodOverride", BehaviorConstant(RPI::Cullable::NoLodOverride)) + behaviorContext->ConstantProperty("DefaultLodOverride", BehaviorConstant(0)) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Category, "render") ->Attribute(AZ::Script::Attributes::Module, "render"); - behaviorContext->ConstantProperty("DefaultLodType", BehaviorConstant(RPI::Cullable::DefaultLodType)) + behaviorContext->ConstantProperty("DefaultLodType", BehaviorConstant(RPI::Cullable::LodType::Default)) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Category, "render") ->Attribute(AZ::Script::Attributes::Module, "render"); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h index 1b479ed3eb..5f38088ca3 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h @@ -44,6 +44,9 @@ namespace AZ // Editor helper functions bool IsAssetSet(); + bool LodTypeIsScreenCoverage(); + bool LodTypeIsSpecificLOD(); + bool ShowLodConfig(); AZStd::vector> GetLodOverrideValues(); AZStd::vector> GetLodTypeValues(); @@ -52,10 +55,10 @@ namespace AZ bool m_excludeFromReflectionCubeMaps = false; bool m_useForwardPassIblSpecular = false; - RPI::Cullable::LodType m_lodType = RPI::Cullable::DefaultLodType; - RPI::Cullable::LodOverride m_lodOverride = RPI::Cullable::NoLodOverride; - float m_minimumScreenCoverage = RPI::Cullable::LodData::DefaultMinimumScreenCoverage; - float m_qualityDecayRate = RPI::Cullable::LodData::DefaultQualityDecayRate; + RPI::Cullable::LodType m_lodType = RPI::Cullable::LodType::Default; + RPI::Cullable::LodOverride m_lodOverride = aznumeric_cast(0); + float m_minimumScreenCoverage = 1.0f / 1080.0f; + float m_qualityDecayRate = 0.5f; }; class MeshComponentController final From cea334dbc40d076b0d4d3fc052f89a660466f662 Mon Sep 17 00:00:00 2001 From: Kyle B Date: Wed, 11 Aug 2021 22:23:06 -0700 Subject: [PATCH 08/26] Fixed enum value problems Signed-off-by: Kyle B --- .../Code/Source/Mesh/EditorMeshComponent.cpp | 4 +++- .../Code/Source/Mesh/MeshComponentController.cpp | 13 ++----------- .../Code/Source/Mesh/MeshComponentController.h | 1 - 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp index ff0741fc31..63b32f6892 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp @@ -80,7 +80,9 @@ namespace AZ "Renders IBL specular reflections in the forward pass, using only the most influential probe (based on the position of the entity) and the global IBL cubemap. Can reduce rendering costs, but only recommended for static objects that are affected by at most one reflection probe.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodType, "Lod Type", "Lod Method.") - ->Attribute(AZ::Edit::Attributes::EnumValues, &MeshComponentConfig::GetLodTypeValues) + ->EnumAttribute(RPI::Cullable::LodType::Default, "Default") + ->EnumAttribute(RPI::Cullable::LodType::ScreenCoverage, "Screen Coverage") + ->EnumAttribute(RPI::Cullable::LodType::SpecificLod, "Specific Lod") ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::IsAssetSet) ->ClassElement(AZ::Edit::ClassElements::Group, "Lod Configuration") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 3d049d0f97..9aa3685c34 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -54,8 +54,7 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - //->Version(2, &MeshComponentControllerVersionUtility::VersionConverter) - ->Version(1) + ->Version(2, &MeshComponentControllerVersionUtility::VersionConverter) ->Field("ModelAsset", &MeshComponentConfig::m_modelAsset) ->Field("SortKey", &MeshComponentConfig::m_sortKey) ->Field("ExcludeFromReflectionCubeMaps", &MeshComponentConfig::m_excludeFromReflectionCubeMaps) @@ -65,6 +64,7 @@ namespace AZ ->Field("MinimumScreenCoverage", &MeshComponentConfig::m_minimumScreenCoverage) ->Field("QualityDecayRate", &MeshComponentConfig::m_qualityDecayRate); } + } bool MeshComponentConfig::IsAssetSet() @@ -120,15 +120,6 @@ namespace AZ return values; } - AZStd::vector> MeshComponentConfig::GetLodTypeValues() - { - return { - {aznumeric_cast(0), "Default"}, - {aznumeric_cast(1), "Screen Coverage" }, - {aznumeric_cast(2), "Specific Lod" } - }; - } - MeshComponentController::~MeshComponentController() { // Release memory, disconnect from buses in the right order and broadcast events so that other components are aware. diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h index 5f38088ca3..aba560b6e8 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h @@ -48,7 +48,6 @@ namespace AZ bool LodTypeIsSpecificLOD(); bool ShowLodConfig(); AZStd::vector> GetLodOverrideValues(); - AZStd::vector> GetLodTypeValues(); Data::Asset m_modelAsset = { AZ::Data::AssetLoadBehavior::QueueLoad }; RHI::DrawItemSortKey m_sortKey = 0; From bdbab1090a6970f057de0ac65e074204eefdbc2c Mon Sep 17 00:00:00 2001 From: Kyle B Date: Thu, 12 Aug 2021 14:49:25 -0700 Subject: [PATCH 09/26] removed accidental file addition Signed-off-by: Kyle B --- .../QuadSphere_Default.material | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/QuadSphere_Default.material diff --git a/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/QuadSphere_Default.material b/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/QuadSphere_Default.material deleted file mode 100644 index 4905c302fe..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/QuadSphere_Default.material +++ /dev/null @@ -1,28 +0,0 @@ -{ - "description": "", - "materialType": "Materials/Types/StandardPBR.materialtype", - "parentMaterial": "", - "propertyLayoutVersion": 3, - "properties": { - "baseColor": { - "color": [ - 0.800000011920929, - 0.800000011920929, - 0.800000011920929, - 1.0 - ], - "textureMap": "MaterialEditor/ViewportModels/_dev_shaderball_00_basecolor.png" - }, - "emissive": { - "color": [ - 0.0, - 0.0, - 0.0, - 1.0 - ] - }, - "opacity": { - "factor": 1.0 - } - } -} \ No newline at end of file From 6acbea722ef101227896366bd6e9518f9d691da7 Mon Sep 17 00:00:00 2001 From: Kyle B Date: Thu, 12 Aug 2021 18:15:17 -0700 Subject: [PATCH 10/26] minor syntax changes and adding a refresh tree attributeto the editor component Signed-off-by: Kyle B --- .../Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h | 2 +- .../Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h | 2 +- .../Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp | 2 +- .../CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index daf4a493c2..a448f7121f 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -155,7 +155,7 @@ namespace AZ void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) override; RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) override; - void SetMeshLodConfiguration(const MeshHandle& meshHandle, RPI::Cullable::LodConfiguration meshLodConfig); + void SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration meshLodConfig); RPI::Cullable::LodConfiguration GetMeshLodConfiguration(const MeshHandle& meshHandle) const; void SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps) override; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h index 8c7a200ff5..c341cd8854 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h @@ -95,7 +95,7 @@ namespace AZ //! Gets the sort key for a given mesh handle. virtual RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) = 0; //! Sets LOD mesh configurations to be used in the Mesh Feature Processor - virtual void SetMeshLodConfiguration(const MeshHandle& meshHandle, RPI::Cullable::LodConfiguration meshLodConfig) = 0; + virtual void SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration meshLodConfig) = 0; //! Gets the LOD mesh configurations being used in the Mesh Feature Processor virtual RPI::Cullable::LodConfiguration GetMeshLodConfiguration(const MeshHandle& meshHandle) const = 0; //! Sets the option to exclude this mesh from baked reflection probe cubemaps diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 363723f7da..e07c7a0309 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -359,7 +359,7 @@ namespace AZ } } - void MeshFeatureProcessor::SetMeshLodConfiguration(const MeshHandle& meshHandle, RPI::Cullable::LodConfiguration meshLodConfig) + void MeshFeatureProcessor::SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration meshLodConfig) { if (meshHandle.IsValid()) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp index 63b32f6892..8f81bd620d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp @@ -84,6 +84,7 @@ namespace AZ ->EnumAttribute(RPI::Cullable::LodType::ScreenCoverage, "Screen Coverage") ->EnumAttribute(RPI::Cullable::LodType::SpecificLod, "Specific Lod") ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::IsAssetSet) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::EntireTree) ->ClassElement(AZ::Edit::ClassElements::Group, "Lod Configuration") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::ShowLodConfig) From 1322a59e9e1ea9c1368da59c8a180bf513ee54a3 Mon Sep 17 00:00:00 2001 From: Pinfel Date: Sat, 14 Aug 2021 16:20:15 -0400 Subject: [PATCH 11/26] Corrected audio component links to documentation Note that the "Audio Animation" component has no documentation so I did not add for it. Signed-off-by: Pinfel --- Gems/LmbrCentral/Code/Source/Audio/AudioProxyComponent.cpp | 2 +- .../Code/Source/Audio/EditorAudioAreaEnvironmentComponent.cpp | 2 +- .../Code/Source/Audio/EditorAudioEnvironmentComponent.cpp | 2 +- .../Code/Source/Audio/EditorAudioListenerComponent.cpp | 2 +- .../Code/Source/Audio/EditorAudioMultiPositionComponent.cpp | 2 +- .../Code/Source/Audio/EditorAudioPreloadComponent.cpp | 2 +- Gems/LmbrCentral/Code/Source/Audio/EditorAudioRtpcComponent.cpp | 2 +- .../Code/Source/Audio/EditorAudioSwitchComponent.cpp | 2 +- .../Code/Source/Audio/EditorAudioTriggerComponent.cpp | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gems/LmbrCentral/Code/Source/Audio/AudioProxyComponent.cpp b/Gems/LmbrCentral/Code/Source/Audio/AudioProxyComponent.cpp index 8be8aa042e..659fff55d9 100644 --- a/Gems/LmbrCentral/Code/Source/Audio/AudioProxyComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Audio/AudioProxyComponent.cpp @@ -39,7 +39,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AudioProxy.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AddableByUser, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio-proxy/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio/proxy/") ; } } diff --git a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioAreaEnvironmentComponent.cpp b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioAreaEnvironmentComponent.cpp index 2b4741331f..7861244ea4 100644 --- a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioAreaEnvironmentComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioAreaEnvironmentComponent.cpp @@ -40,7 +40,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AudioAreaEnvironment.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio-area-environment/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio/area-environment/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorAudioAreaEnvironmentComponent::m_broadPhaseTriggerArea, "Broad-phase trigger area", "The entity that contains a Trigger Area component for broad-phase checks") ->Attribute(AZ::Edit::Attributes::RequiredService, AZ_CRC("ProximityTriggerService", 0x561f262c)) diff --git a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioEnvironmentComponent.cpp b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioEnvironmentComponent.cpp index b4dd5c4d74..b2633a9cb0 100644 --- a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioEnvironmentComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioEnvironmentComponent.cpp @@ -33,7 +33,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AudioEnvironment.png") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio-environment/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio/environment/") ->DataElement("AudioControl", &EditorAudioEnvironmentComponent::m_defaultEnvironment, "Default Environment", "Name of the default ATL Environment control to use") ; } diff --git a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioListenerComponent.cpp b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioListenerComponent.cpp index 205267db73..c9f80ed398 100644 --- a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioListenerComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioListenerComponent.cpp @@ -36,7 +36,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AudioListener.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio-listener/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio/listener/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorAudioListenerComponent::m_rotationEntity, "Rotation Entity", "The Entity whose rotation the audio listener will adopt. If none set, will assume 'this' Entity") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorAudioListenerComponent::m_positionEntity, diff --git a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioMultiPositionComponent.cpp b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioMultiPositionComponent.cpp index 987fa6e0e4..51386b1c02 100644 --- a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioMultiPositionComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioMultiPositionComponent.cpp @@ -38,7 +38,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AudioMultiPosition.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - // Followup: Need Help URL + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio/multi-position/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorAudioMultiPositionComponent::m_entityRefs, "Entity References", "The entities from which positions will be obtained for multi-position audio") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorAudioMultiPositionComponent::m_behaviorType, "Behavior Type", "Determines how multi-postion sounds are treated, Separate or Blended") ; diff --git a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioPreloadComponent.cpp b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioPreloadComponent.cpp index a5d137c1b2..a24acac292 100644 --- a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioPreloadComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioPreloadComponent.cpp @@ -43,7 +43,7 @@ namespace LmbrCentral // Icon todo: //->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AudioPreload.png") - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio-preload/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio/preload/") ->DataElement("AudioControl", &EditorAudioPreloadComponent::m_defaultPreload, "Preload Name", "The default ATL Preload control to use") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorAudioPreloadComponent::m_loadType, "Load Type", "Automatically when the component activates/deactivates, or Manually at user's request") diff --git a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioRtpcComponent.cpp b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioRtpcComponent.cpp index ab98692a50..4426c21ff6 100644 --- a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioRtpcComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioRtpcComponent.cpp @@ -34,7 +34,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AudioRtpc.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio-rtpc/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio/rtpc/") ->DataElement("AudioControl", &EditorAudioRtpcComponent::m_defaultRtpc, "Default Rtpc", "The default ATL Rtpc control to use") ; } diff --git a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioSwitchComponent.cpp b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioSwitchComponent.cpp index 6ea89ee31e..1aafbd5c21 100644 --- a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioSwitchComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioSwitchComponent.cpp @@ -34,7 +34,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AudioSwitch.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio-switch/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio/switch/") ->DataElement("AudioControl", &EditorAudioSwitchComponent::m_defaultSwitch, "Default Switch", "The default ATL Switch to use when Activated") ->DataElement("AudioControl", &EditorAudioSwitchComponent::m_defaultState, "Default State", "The default ATL State to set on the default Switch when Activated") ; diff --git a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioTriggerComponent.cpp b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioTriggerComponent.cpp index e38caf303b..adecf3c4d0 100644 --- a/Gems/LmbrCentral/Code/Source/Audio/EditorAudioTriggerComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Audio/EditorAudioTriggerComponent.cpp @@ -43,7 +43,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AudioTrigger.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio-trigger/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/audio/trigger/") ->DataElement("AudioControl", &EditorAudioTriggerComponent::m_defaultPlayTrigger, "Default 'play' Trigger", "The default ATL Trigger control used by 'Play'") ->DataElement("AudioControl", &EditorAudioTriggerComponent::m_defaultStopTrigger, "Default 'stop' Trigger", "The default ATL Trigger control used by 'Stop'") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorAudioTriggerComponent::m_obstructionType, "Obstruction Type", "Ray-casts used in calculation of obstruction and occlusion") From e2a9c58cae300317f0b3b80ea3cccaae26926512 Mon Sep 17 00:00:00 2001 From: Kyle B Date: Mon, 16 Aug 2021 23:01:18 -0700 Subject: [PATCH 12/26] fixed unnessisary qualifier error Signed-off-by: Kyle B --- .../CommonFeatures/Code/Source/Mesh/MeshComponentController.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h index aba560b6e8..c7f9c8f993 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h @@ -148,7 +148,7 @@ namespace AZ void UnregisterModel(); void RefreshModelRegistration(); - RPI::Cullable::LodConfiguration MeshComponentController::GetMeshLodConfiguration() const; + RPI::Cullable::LodConfiguration GetMeshLodConfiguration() const; void HandleNonUniformScaleChange(const AZ::Vector3& nonUniformScale); From 01ad7c5e4efcb95a185588c5e9ff13633e7667fd Mon Sep 17 00:00:00 2001 From: Kyle B Date: Mon, 16 Aug 2021 23:09:25 -0700 Subject: [PATCH 13/26] fixed namespace issue with the mocks Signed-off-by: Kyle B --- .../Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h index 0c03e767e7..75ce42daed 100644 --- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h @@ -33,8 +33,8 @@ namespace UnitTest MOCK_CONST_METHOD1(GetLocalAabb, AZ::Aabb(const MeshHandle&)); MOCK_METHOD2(SetSortKey, void (const MeshHandle&, AZ::RHI::DrawItemSortKey)); MOCK_CONST_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&)); - MOCK_METHOD2(SetMeshLodConfiguration, void(const MeshHandle&, RPI::Cullable::LodConfiguration)); - MOCK_CONST_METHOD1(GetMeshLodConfiguration, RPI::Cullable::LodConfiguration(const MeshHandle&)); + MOCK_METHOD2(SetMeshLodConfiguration, void(const MeshHandle&, AZ::RPI::Cullable::LodConfiguration)); + MOCK_CONST_METHOD1(GetMeshLodConfiguration, AZ::RPI::Cullable::LodConfiguration(const MeshHandle&)); MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Render::MaterialAssignmentMap&)); MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Data::Instance&)); MOCK_METHOD2(SetRayTracingEnabled, void (const MeshHandle&, bool)); From c515ead27e1a64f146529f6933214be23972c0d5 Mon Sep 17 00:00:00 2001 From: Kyle B Date: Tue, 17 Aug 2021 22:44:41 -0700 Subject: [PATCH 14/26] attempt to fixed mock errors Signed-off-by: Kyle B --- .../Code/Mocks/MockMeshFeatureProcessor.h | 2 +- Gems/Vegetation/Code/Tests/VegetationMocks.h | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h index 75ce42daed..49d615a37f 100644 --- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h @@ -33,7 +33,7 @@ namespace UnitTest MOCK_CONST_METHOD1(GetLocalAabb, AZ::Aabb(const MeshHandle&)); MOCK_METHOD2(SetSortKey, void (const MeshHandle&, AZ::RHI::DrawItemSortKey)); MOCK_CONST_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&)); - MOCK_METHOD2(SetMeshLodConfiguration, void(const MeshHandle&, AZ::RPI::Cullable::LodConfiguration)); + MOCK_METHOD2(SetMeshLodConfiguration, void(const MeshHandle&, const AZ::RPI::Cullable::LodConfiguration)); MOCK_CONST_METHOD1(GetMeshLodConfiguration, AZ::RPI::Cullable::LodConfiguration(const MeshHandle&)); MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Render::MaterialAssignmentMap&)); MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Data::Instance&)); diff --git a/Gems/Vegetation/Code/Tests/VegetationMocks.h b/Gems/Vegetation/Code/Tests/VegetationMocks.h index 37bacef21a..cd438335c6 100644 --- a/Gems/Vegetation/Code/Tests/VegetationMocks.h +++ b/Gems/Vegetation/Code/Tests/VegetationMocks.h @@ -554,6 +554,16 @@ namespace UnitTest return m_drawItemSortKeyOutput; } + AZ::RPI::Cullable::LodType m_lodTypeOutput; + void SetLodOverride(AZ::RPI::Cullable::LodType lodType) override + { + m_lodTypeOutput = lodType; + } + AZ::RPI::Cullable::LodType GetLodType() const override + { + return m_lodTypeOutput; + } + AZ::RPI::Cullable::LodOverride m_lodOverrideOutput; void SetLodOverride(AZ::RPI::Cullable::LodOverride lodOverride) override { @@ -563,6 +573,26 @@ namespace UnitTest { return m_lodOverrideOutput; } + + float m_minimumScreenCoverageOutput; + void SetMinimumScreenCoverage(float minimumScreenCoverage) override + { + m_minimumScreenCoverageOutput = minimumScreenCoverage; + } + float GetMinimumScreenCoverage() const override + { + return m_minimumScreenCoverageOutput; + } + + float m_qualityDecayRateOutput; + void SetQualityDecayRate(float qualityDecayRate) override + { + m_qualityDecayRateOutput = qualityDecayRate; + } + float GetQualityDecayRate() const override + { + return m_qualityDecayRateOutput; + } }; struct MockTransformBus From 13f4f3b37a70f82bbce1acbfdeb2ea3dccfcbb4a Mon Sep 17 00:00:00 2001 From: Kyle B Date: Wed, 18 Aug 2021 19:35:51 -0700 Subject: [PATCH 15/26] fixed typo in vegitation mock Signed-off-by: Kyle B --- Gems/Vegetation/Code/Tests/VegetationMocks.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Vegetation/Code/Tests/VegetationMocks.h b/Gems/Vegetation/Code/Tests/VegetationMocks.h index cd438335c6..ebc51d1b3b 100644 --- a/Gems/Vegetation/Code/Tests/VegetationMocks.h +++ b/Gems/Vegetation/Code/Tests/VegetationMocks.h @@ -555,7 +555,7 @@ namespace UnitTest } AZ::RPI::Cullable::LodType m_lodTypeOutput; - void SetLodOverride(AZ::RPI::Cullable::LodType lodType) override + void SetLodType(AZ::RPI::Cullable::LodType lodType) override { m_lodTypeOutput = lodType; } From e410eecd93c5db984cfab09374bfab64df8d1cb2 Mon Sep 17 00:00:00 2001 From: Kyle B Date: Thu, 19 Aug 2021 23:41:30 -0700 Subject: [PATCH 16/26] fixed mesh feature processor abstract interface Signed-off-by: Kyle B --- .../Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h | 6 +++--- .../Atom/Feature/Mesh/MeshFeatureProcessorInterface.h | 4 ++-- .../Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h | 2 +- .../Common/Code/Source/Mesh/MeshFeatureProcessor.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index a448f7121f..389c5902f9 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -153,10 +153,10 @@ namespace AZ AZ::Aabb GetLocalAabb(const MeshHandle& meshHandle) const override; void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) override; - RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) override; + RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) const override; - void SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration meshLodConfig); - RPI::Cullable::LodConfiguration GetMeshLodConfiguration(const MeshHandle& meshHandle) const; + void SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration& meshLodConfig) override; + RPI::Cullable::LodConfiguration GetMeshLodConfiguration(const MeshHandle& meshHandle) const override; void SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps) override; void SetRayTracingEnabled(const MeshHandle& meshHandle, bool rayTracingEnabled) override; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h index c341cd8854..cffbe5c3c5 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h @@ -93,9 +93,9 @@ namespace AZ //! Sets the sort key for a given mesh handle. virtual void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) = 0; //! Gets the sort key for a given mesh handle. - virtual RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) = 0; + virtual RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) const = 0; //! Sets LOD mesh configurations to be used in the Mesh Feature Processor - virtual void SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration meshLodConfig) = 0; + virtual void SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration& meshLodConfig) = 0; //! Gets the LOD mesh configurations being used in the Mesh Feature Processor virtual RPI::Cullable::LodConfiguration GetMeshLodConfiguration(const MeshHandle& meshHandle) const = 0; //! Sets the option to exclude this mesh from baked reflection probe cubemaps diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h index 49d615a37f..35e399997f 100644 --- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h @@ -33,7 +33,7 @@ namespace UnitTest MOCK_CONST_METHOD1(GetLocalAabb, AZ::Aabb(const MeshHandle&)); MOCK_METHOD2(SetSortKey, void (const MeshHandle&, AZ::RHI::DrawItemSortKey)); MOCK_CONST_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&)); - MOCK_METHOD2(SetMeshLodConfiguration, void(const MeshHandle&, const AZ::RPI::Cullable::LodConfiguration)); + MOCK_METHOD2(SetMeshLodConfiguration, void(const MeshHandle&, const AZ::RPI::Cullable::LodConfiguration&)); MOCK_CONST_METHOD1(GetMeshLodConfiguration, AZ::RPI::Cullable::LodConfiguration(const MeshHandle&)); MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Render::MaterialAssignmentMap&)); MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Data::Instance&)); diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index e07c7a0309..18b87d0cea 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -346,7 +346,7 @@ namespace AZ } } - RHI::DrawItemSortKey MeshFeatureProcessor::GetSortKey(const MeshHandle& meshHandle) + RHI::DrawItemSortKey MeshFeatureProcessor::GetSortKey(const MeshHandle& meshHandle) const { if (meshHandle.IsValid()) { @@ -359,7 +359,7 @@ namespace AZ } } - void MeshFeatureProcessor::SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration meshLodConfig) + void MeshFeatureProcessor::SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration& meshLodConfig) { if (meshHandle.IsValid()) { From 8ab9a88683f98e69703857e716ca43a33c7f9431 Mon Sep 17 00:00:00 2001 From: Kyle B Date: Sat, 21 Aug 2021 00:19:07 -0700 Subject: [PATCH 17/26] added cast to version change system lodoverride Signed-off-by: Kyle B --- .../CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 11ac73d034..b1bfb30285 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -38,7 +38,7 @@ namespace AZ { if (classElement.GetVersion() < 2) { - RPI::Cullable::LodOverride lodOverride = classElement.FindElement(AZ_CRC("LodOverride")); + RPI::Cullable::LodOverride lodOverride = aznumeric_cast(classElement.FindElement(AZ_CRC("LodOverride"))); static constexpr uint8_t old_NoLodOverride = AZStd::numeric_limits ::max(); if (lodOverride == old_NoLodOverride) { From e3a7e7cd30720abb32deef6007a69794f06e0ae8 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sat, 21 Aug 2021 17:50:31 -0500 Subject: [PATCH 18/26] copied main window class from material editor Signed-off-by: Guthrie Adams --- .../Document/AtomToolsDocumentMainWindow.h | 100 ++++ .../Document/AtomToolsDocumentMainWindow.cpp | 531 ++++++++++++++++++ .../Code/atomtoolsframework_files.cmake | 2 + 3 files changed, 633 insertions(+) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h new file mode 100644 index 0000000000..b7d0cbf8da --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h @@ -0,0 +1,100 @@ +/* + * 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 + +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT +#include +#include +AZ_POP_DISABLE_WARNING +#endif + +namespace MaterialEditor +{ + /** + * MaterialEditorWindow is the main class. Its responsibility is limited to initializing and connecting + * its panels, managing selection of assets, and performing high-level actions like saving. It contains... + * 1) MaterialBrowser - The user browses for Material (.material) assets. + * 2) MaterialViewport - The user can see the selected Material applied to a model. + * 3) MaterialPropertyInspector - The user edits the properties of the selected Material. + */ + class MaterialEditorWindow + : public AtomToolsFramework::AtomToolsMainWindow + , private AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler + { + Q_OBJECT + public: + AZ_CLASS_ALLOCATOR(MaterialEditorWindow, AZ::SystemAllocator, 0); + + using Base = AtomToolsFramework::AtomToolsMainWindow; + + MaterialEditorWindow(QWidget* parent = 0); + ~MaterialEditorWindow(); + + private: + void ResizeViewportRenderTarget(uint32_t width, uint32_t height) override; + void LockViewportRenderTargetSize(uint32_t width, uint32_t height) override; + void UnlockViewportRenderTargetSize() override; + + // AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler overrides... + void OnDocumentOpened(const AZ::Uuid& documentId) override; + void OnDocumentClosed(const AZ::Uuid& documentId) override; + void OnDocumentModified(const AZ::Uuid& documentId) override; + void OnDocumentUndoStateChanged(const AZ::Uuid& documentId) override; + void OnDocumentSaved(const AZ::Uuid& documentId) override; + + void CreateMenu() override; + void CreateTabBar() override; + + QString GetDocumentPath(const AZ::Uuid& documentId) const; + + void OpenTabContextMenu() override; + + void closeEvent(QCloseEvent* closeEvent) override; + + MaterialViewportWidget* m_materialViewport = nullptr; + MaterialEditorToolBar* m_toolBar = nullptr; + + QMenu* m_menuFile = {}; + QAction* m_actionNew = {}; + QAction* m_actionOpen = {}; + QAction* m_actionOpenRecent = {}; + QAction* m_actionClose = {}; + QAction* m_actionCloseAll = {}; + QAction* m_actionCloseOthers = {}; + QAction* m_actionSave = {}; + QAction* m_actionSaveAsCopy = {}; + QAction* m_actionSaveAsChild = {}; + QAction* m_actionSaveAll = {}; + QAction* m_actionExit = {}; + + QMenu* m_menuEdit = {}; + QAction* m_actionUndo = {}; + QAction* m_actionRedo = {}; + QAction* m_actionSettings = {}; + + QMenu* m_menuView = {}; + QAction* m_actionAssetBrowser = {}; + QAction* m_actionInspector = {}; + QAction* m_actionConsole = {}; + QAction* m_actionPythonTerminal = {}; + QAction* m_actionPerfMonitor = {}; + QAction* m_actionViewportSettings = {}; + QAction* m_actionNextTab = {}; + QAction* m_actionPreviousTab = {}; + + QMenu* m_menuHelp = {}; + QAction* m_actionHelp = {}; + QAction* m_actionAbout = {}; + }; +} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp new file mode 100644 index 0000000000..8922591580 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp @@ -0,0 +1,531 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT +#include +#include +#include +#include +#include +#include +AZ_POP_DISABLE_WARNING + +namespace MaterialEditor +{ + MaterialEditorWindow::MaterialEditorWindow(QWidget* parent /* = 0 */) + : AtomToolsFramework::AtomToolsMainWindow(parent) + { + resize(1280, 1024); + + // Among other things, we need the window wrapper to save the main window size, position, and state + auto mainWindowWrapper = + new AzQtComponents::WindowDecorationWrapper(AzQtComponents::WindowDecorationWrapper::OptionAutoTitleBarButtons); + mainWindowWrapper->setGuest(this); + mainWindowWrapper->enableSaveRestoreGeometry("O3DE", "MaterialEditor", "mainWindowGeometry"); + + // set the style sheet for RPE highlighting and other styling + AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral(":/MaterialEditor.qss")); + + QApplication::setWindowIcon(QIcon(":/Icons/materialeditor.svg")); + + AZ::Name apiName = AZ::RHI::Factory::Get().GetName(); + if (!apiName.IsEmpty()) + { + QString title = QString{ "%1 (%2)" }.arg(QApplication::applicationName()).arg(apiName.GetCStr()); + setWindowTitle(title); + } + else + { + AZ_Assert(false, "Render API name not found"); + setWindowTitle(QApplication::applicationName()); + } + + setObjectName("MaterialEditorWindow"); + + m_toolBar = new MaterialEditorToolBar(this); + m_toolBar->setObjectName("ToolBar"); + addToolBar(m_toolBar); + + CreateMenu(); + CreateTabBar(); + + m_materialViewport = new MaterialViewportWidget(centralWidget()); + m_materialViewport->setObjectName("Viewport"); + m_materialViewport->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + centralWidget()->layout()->addWidget(m_materialViewport); + + AddDockWidget("Asset Browser", new MaterialBrowserWidget, Qt::BottomDockWidgetArea, Qt::Vertical); + AddDockWidget("Inspector", new MaterialInspector, Qt::RightDockWidgetArea, Qt::Horizontal); + AddDockWidget("Viewport Settings", new ViewportSettingsInspector, Qt::LeftDockWidgetArea, Qt::Horizontal); + AddDockWidget("Performance Monitor", new PerformanceMonitorWidget, Qt::RightDockWidgetArea, Qt::Horizontal); + AddDockWidget("Python Terminal", new AzToolsFramework::CScriptTermDialog, Qt::BottomDockWidgetArea, Qt::Horizontal); + + SetDockWidgetVisible("Viewport Settings", false); + SetDockWidgetVisible("Performance Monitor", false); + SetDockWidgetVisible("Python Terminal", false); + + // Restore geometry and show the window + mainWindowWrapper->showFromSettings(); + + // Restore additional state for docked windows + auto windowSettings = AZ::UserSettings::CreateFind( + AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL); + + if (!windowSettings->m_mainWindowState.empty()) + { + QByteArray windowState(windowSettings->m_mainWindowState.data(), static_cast(windowSettings->m_mainWindowState.size())); + m_advancedDockManager->restoreState(windowState); + } + + AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); + OnDocumentOpened(AZ::Uuid::CreateNull()); + } + + MaterialEditorWindow::~MaterialEditorWindow() + { + AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); + } + + + void MaterialEditorWindow::ResizeViewportRenderTarget(uint32_t width, uint32_t height) + { + QSize requestedViewportSize = QSize(width, height) / devicePixelRatioF(); + QSize currentViewportSize = m_materialViewport->size(); + QSize offset = requestedViewportSize - currentViewportSize; + QSize requestedWindowSize = size() + offset; + resize(requestedWindowSize); + + AZ_Assert( + m_materialViewport->size() == requestedViewportSize, + "Resizing the window did not give the expected viewport size. Requested %d x %d but got %d x %d.", + requestedViewportSize.width(), requestedViewportSize.height(), m_materialViewport->size().width(), + m_materialViewport->size().height()); + + QSize newDeviceSize = m_materialViewport->size(); + AZ_Warning( + "Material Editor", static_cast(newDeviceSize.width()) == width && static_cast(newDeviceSize.height()) == height, + "Resizing the window did not give the expected frame size. Requested %d x %d but got %d x %d.", width, height, + newDeviceSize.width(), newDeviceSize.height()); + } + + void MaterialEditorWindow::LockViewportRenderTargetSize(uint32_t width, uint32_t height) + { + m_materialViewport->LockRenderTargetSize(width, height); + } + + void MaterialEditorWindow::UnlockViewportRenderTargetSize() + { + m_materialViewport->UnlockRenderTargetSize(); + } + + void MaterialEditorWindow::closeEvent(QCloseEvent* closeEvent) + { + bool didClose = true; + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); + if (!didClose) + { + closeEvent->ignore(); + return; + } + + // Capture docking state before shutdown + auto windowSettings = AZ::UserSettings::CreateFind( + AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL); + + QByteArray windowState = m_advancedDockManager->saveState(); + windowSettings->m_mainWindowState.assign(windowState.begin(), windowState.end()); + + AtomToolsFramework::AtomToolsMainWindowNotificationBus::Broadcast( + &AtomToolsFramework::AtomToolsMainWindowNotifications::OnMainWindowClosing); + } + + void MaterialEditorWindow::OnDocumentOpened(const AZ::Uuid& documentId) + { + bool isOpen = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsOpen); + bool isSavable = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsSavable); + bool isModified = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); + bool canUndo = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo); + bool canRedo = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo); + AZStd::string absolutePath; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + + // Update UI to display the new document + if (!documentId.IsNull() && isOpen) + { + // Create a new tab for the document ID and assign it's label to the file name of the document. + AddTabForDocumentId(documentId, filename, absolutePath, [this]{ + // The tab widget requires a dummy page per tab + auto contentWidget = new QWidget(centralWidget()); + contentWidget->setContentsMargins(0, 0, 0, 0); + contentWidget->setFixedSize(0, 0); + return contentWidget; + }); + } + + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + + const bool hasTabs = m_tabWidget->count() > 0; + + // Update menu options + m_actionNew->setEnabled(true); + m_actionOpen->setEnabled(true); + m_actionOpenRecent->setEnabled(false); + m_actionClose->setEnabled(hasTabs); + m_actionCloseAll->setEnabled(hasTabs); + m_actionCloseOthers->setEnabled(hasTabs); + + m_actionSave->setEnabled(isOpen && isSavable); + m_actionSaveAsCopy->setEnabled(isOpen && isSavable); + m_actionSaveAsChild->setEnabled(isOpen); + m_actionSaveAll->setEnabled(hasTabs); + + m_actionExit->setEnabled(true); + + m_actionUndo->setEnabled(canUndo); + m_actionRedo->setEnabled(canRedo); + m_actionSettings->setEnabled(true); + + m_actionAssetBrowser->setEnabled(true); + m_actionInspector->setEnabled(true); + m_actionConsole->setEnabled(false); + m_actionPythonTerminal->setEnabled(true); + m_actionPerfMonitor->setEnabled(true); + m_actionViewportSettings->setEnabled(true); + m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); + m_actionNextTab->setEnabled(m_tabWidget->count() > 1); + + m_actionAbout->setEnabled(false); + + activateWindow(); + raise(); + + const QString documentPath = GetDocumentPath(documentId); + if (!documentPath.isEmpty()) + { + SetStatusMessage(tr("Document opened: %1").arg(documentPath)); + } + } + + void MaterialEditorWindow::OnDocumentClosed(const AZ::Uuid& documentId) + { + RemoveTabForDocumentId(documentId); + SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); + } + + void MaterialEditorWindow::OnDocumentModified(const AZ::Uuid& documentId) + { + bool isModified = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); + AZStd::string absolutePath; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + } + + void MaterialEditorWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) + { + if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex())) + { + bool canUndo = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo); + bool canRedo = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo); + m_actionUndo->setEnabled(canUndo); + m_actionRedo->setEnabled(canRedo); + } + } + + void MaterialEditorWindow::OnDocumentSaved(const AZ::Uuid& documentId) + { + bool isModified = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); + AZStd::string absolutePath; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); + } + + void MaterialEditorWindow::CreateMenu() + { + Base::CreateMenu(); + + // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries + m_menuFile = menuBar()->addMenu("&File"); + + m_actionNew = m_menuFile->addAction("&New...", [this]() { + CreateMaterialDialog createDialog(this); + createDialog.adjustSize(); + + if (createDialog.exec() == QDialog::Accepted && + !createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() && + !createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty()) + { + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, + createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(), + createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData()); + } + }, QKeySequence::New); + + m_actionOpen = m_menuFile->addAction("&Open...", [this]() { + const AZStd::vector assetTypes = { azrtti_typeid() }; + const AZStd::string filePath = AtomToolsFramework::GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); + if (!filePath.empty()) + { + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, filePath); + } + }, QKeySequence::Open); + + m_actionOpenRecent = m_menuFile->addAction("Open &Recent"); + + m_menuFile->addSeparator(); + + m_actionSave = m_menuFile->addAction("&Save", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + bool result = false; + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); + if (!result) + { + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::Save); + + m_actionSaveAsCopy = m_menuFile->addAction("Save &As...", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const QString documentPath = GetDocumentPath(documentId); + + bool result = false; + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy, + documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); + if (!result) + { + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::SaveAs); + + m_actionSaveAsChild = m_menuFile->addAction("Save As &Child...", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const QString documentPath = GetDocumentPath(documentId); + + bool result = false; + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsChild, + documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); + if (!result) + { + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); + } + }); + + m_actionSaveAll = m_menuFile->addAction("Save A&ll", [this]() { + bool result = false; + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments); + if (!result) + { + SetStatusError(tr("Document save all failed")); + } + }); + + m_menuFile->addSeparator(); + + m_actionClose = m_menuFile->addAction("&Close", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + }, QKeySequence::Close); + + m_actionCloseAll = m_menuFile->addAction("Close All", [this]() { + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); + }); + + m_actionCloseOthers = m_menuFile->addAction("Close Others", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); + }); + + m_menuFile->addSeparator(); + + m_menuFile->addAction("Run &Python...", [this]() { + const QString script = QFileDialog::getOpenFileName(this, "Run Script", QString(), QString("*.py")); + if (!script.isEmpty()) + { + AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilename, script.toUtf8().constData()); + } + }); + + m_menuFile->addSeparator(); + + m_actionExit = m_menuFile->addAction("E&xit", [this]() { + close(); + }, QKeySequence::Quit); + + m_menuEdit = menuBar()->addMenu("&Edit"); + + m_actionUndo = m_menuEdit->addAction("&Undo", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + bool result = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Undo); + if (!result) + { + SetStatusError(tr("Document undo failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::Undo); + + m_actionRedo = m_menuEdit->addAction("&Redo", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + bool result = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Redo); + if (!result) + { + SetStatusError(tr("Document redo failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::Redo); + + m_menuEdit->addSeparator(); + + m_actionSettings = m_menuEdit->addAction("&Settings...", [this]() { + SettingsDialog dialog(this); + dialog.exec(); + }, QKeySequence::Preferences); + m_actionSettings->setEnabled(true); + + m_menuView = menuBar()->addMenu("&View"); + + m_actionAssetBrowser = m_menuView->addAction("&Asset Browser", [this]() { + const AZStd::string label = "Asset Browser"; + SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); + }); + + m_actionInspector = m_menuView->addAction("&Inspector", [this]() { + const AZStd::string label = "Inspector"; + SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); + }); + + m_actionConsole = m_menuView->addAction("&Console", [this]() { + }); + + m_actionPythonTerminal = m_menuView->addAction("Python &Terminal", [this]() { + const AZStd::string label = "Python Terminal"; + SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); + }); + + m_actionPerfMonitor = m_menuView->addAction("Performance &Monitor", [this]() { + const AZStd::string label = "Performance Monitor"; + SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); + }); + + m_actionViewportSettings = m_menuView->addAction("Viewport Settings", [this]() { + const AZStd::string label = "Viewport Settings"; + SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); + }); + + m_menuView->addSeparator(); + + m_actionPreviousTab = m_menuView->addAction("&Previous Tab", [this]() { + SelectPreviousTab(); + }, Qt::CTRL | Qt::SHIFT | Qt::Key_Tab); //QKeySequence::PreviousChild is mapped incorrectly in Qt + + m_actionNextTab = m_menuView->addAction("&Next Tab", [this]() { + SelectNextTab(); + }, Qt::CTRL | Qt::Key_Tab); //QKeySequence::NextChild works as expected but mirroring Previous + + m_menuHelp = menuBar()->addMenu("&Help"); + + m_actionHelp = m_menuHelp->addAction("&Help...", [this]() { + HelpDialog dialog(this); + dialog.exec(); + }); + + m_actionAbout = m_menuHelp->addAction("&About...", [this]() { + }); + } + + void MaterialEditorWindow::CreateTabBar() + { + Base::CreateTabBar(); + + // This signal will be triggered whenever a tab is added, removed, selected, clicked, dragged + // When the last tab is removed tabIndex will be -1 and the document ID will be null + // This should automatically clear the active document + connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int tabIndex) { + const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); + }); + + connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int tabIndex) { + const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + }); + } + + QString MaterialEditorWindow::GetDocumentPath(const AZ::Uuid& documentId) const + { + AZStd::string absolutePath; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Handler::GetAbsolutePath); + return absolutePath.c_str(); + } + + void MaterialEditorWindow::OpenTabContextMenu() + { + const QTabBar* tabBar = m_tabWidget->tabBar(); + const QPoint position = tabBar->mapFromGlobal(QCursor::pos()); + const int clickedTabIndex = tabBar->tabAt(position); + const int currentTabIndex = tabBar->currentIndex(); + if (clickedTabIndex >= 0) + { + QMenu tabMenu; + const QString selectActionName = (currentTabIndex == clickedTabIndex) ? "Select in Browser" : "Select"; + tabMenu.addAction(selectActionName, [this, clickedTabIndex]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); + }); + tabMenu.addAction("Close", [this, clickedTabIndex]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + }); + auto closeOthersAction = tabMenu.addAction("Close Others", [this, clickedTabIndex]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); + }); + closeOthersAction->setEnabled(tabBar->count() > 1); + tabMenu.exec(QCursor::pos()); + } + } +} // namespace MaterialEditor + +#include diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index cd056f5fcf..3d4bb82eec 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -12,6 +12,7 @@ set(FILES Include/AtomToolsFramework/Communication/LocalSocket.h Include/AtomToolsFramework/Debug/TraceRecorder.h Include/AtomToolsFramework/Document/AtomToolsDocument.h + Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h Include/AtomToolsFramework/Document/AtomToolsDocumentSystemSettings.h Include/AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h Include/AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h @@ -38,6 +39,7 @@ set(FILES Source/Communication/LocalSocket.cpp Source/Debug/TraceRecorder.cpp Source/Document/AtomToolsDocument.cpp + Source/Document/AtomToolsDocumentMainWindow.cpp Source/Document/AtomToolsDocumentSystemSettings.cpp Source/Document/AtomToolsDocumentSystemComponent.cpp Source/Document/AtomToolsDocumentSystemComponent.h From 9449b52011c6a155f31a5a16717c27d26440e1f0 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 22 Aug 2021 14:58:24 -0500 Subject: [PATCH 19/26] getting atom tools document main window compiling Signed-off-by: Guthrie Adams --- .../Document/AtomToolsDocumentMainWindow.h | 45 +-- .../Document/AtomToolsDocumentMainWindow.cpp | 295 +++++------------- 2 files changed, 84 insertions(+), 256 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h index b7d0cbf8da..1c8f9a1f55 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h @@ -12,41 +12,27 @@ #include #include #include - -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include -AZ_POP_DISABLE_WARNING #endif -namespace MaterialEditor +namespace AtomToolsFramework { - /** - * MaterialEditorWindow is the main class. Its responsibility is limited to initializing and connecting - * its panels, managing selection of assets, and performing high-level actions like saving. It contains... - * 1) MaterialBrowser - The user browses for Material (.material) assets. - * 2) MaterialViewport - The user can see the selected Material applied to a model. - * 3) MaterialPropertyInspector - The user edits the properties of the selected Material. - */ - class MaterialEditorWindow - : public AtomToolsFramework::AtomToolsMainWindow - , private AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler + //! AtomToolsDocumentMainWindow + class AtomToolsDocumentMainWindow + : public AtomToolsMainWindow + , private AtomToolsDocumentNotificationBus::Handler { Q_OBJECT public: - AZ_CLASS_ALLOCATOR(MaterialEditorWindow, AZ::SystemAllocator, 0); + AZ_CLASS_ALLOCATOR(AtomToolsDocumentMainWindow, AZ::SystemAllocator, 0); - using Base = AtomToolsFramework::AtomToolsMainWindow; + using Base = AtomToolsMainWindow; - MaterialEditorWindow(QWidget* parent = 0); - ~MaterialEditorWindow(); + AtomToolsDocumentMainWindow(QWidget* parent = 0); + ~AtomToolsDocumentMainWindow(); private: - void ResizeViewportRenderTarget(uint32_t width, uint32_t height) override; - void LockViewportRenderTargetSize(uint32_t width, uint32_t height) override; - void UnlockViewportRenderTargetSize() override; - // AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler overrides... + // AtomToolsDocumentNotificationBus::Handler overrides... void OnDocumentOpened(const AZ::Uuid& documentId) override; void OnDocumentClosed(const AZ::Uuid& documentId) override; void OnDocumentModified(const AZ::Uuid& documentId) override; @@ -62,9 +48,6 @@ namespace MaterialEditor void closeEvent(QCloseEvent* closeEvent) override; - MaterialViewportWidget* m_materialViewport = nullptr; - MaterialEditorToolBar* m_toolBar = nullptr; - QMenu* m_menuFile = {}; QAction* m_actionNew = {}; QAction* m_actionOpen = {}; @@ -84,12 +67,6 @@ namespace MaterialEditor QAction* m_actionSettings = {}; QMenu* m_menuView = {}; - QAction* m_actionAssetBrowser = {}; - QAction* m_actionInspector = {}; - QAction* m_actionConsole = {}; - QAction* m_actionPythonTerminal = {}; - QAction* m_actionPerfMonitor = {}; - QAction* m_actionViewportSettings = {}; QAction* m_actionNextTab = {}; QAction* m_actionPreviousTab = {}; @@ -97,4 +74,4 @@ namespace MaterialEditor QAction* m_actionHelp = {}; QAction* m_actionAbout = {}; }; -} // namespace MaterialEditor +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp index 8922591580..502f861f0a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp @@ -6,28 +6,14 @@ * */ -#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 @@ -38,149 +24,48 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnin #include AZ_POP_DISABLE_WARNING -namespace MaterialEditor +namespace AtomToolsFramework { - MaterialEditorWindow::MaterialEditorWindow(QWidget* parent /* = 0 */) - : AtomToolsFramework::AtomToolsMainWindow(parent) + AtomToolsDocumentMainWindow::AtomToolsDocumentMainWindow(QWidget* parent /* = 0 */) + : AtomToolsMainWindow(parent) { - resize(1280, 1024); + setObjectName("AtomToolsDocumentMainWindow"); - // Among other things, we need the window wrapper to save the main window size, position, and state - auto mainWindowWrapper = - new AzQtComponents::WindowDecorationWrapper(AzQtComponents::WindowDecorationWrapper::OptionAutoTitleBarButtons); - mainWindowWrapper->setGuest(this); - mainWindowWrapper->enableSaveRestoreGeometry("O3DE", "MaterialEditor", "mainWindowGeometry"); - - // set the style sheet for RPE highlighting and other styling - AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral(":/MaterialEditor.qss")); - - QApplication::setWindowIcon(QIcon(":/Icons/materialeditor.svg")); - - AZ::Name apiName = AZ::RHI::Factory::Get().GetName(); - if (!apiName.IsEmpty()) - { - QString title = QString{ "%1 (%2)" }.arg(QApplication::applicationName()).arg(apiName.GetCStr()); - setWindowTitle(title); - } - else - { - AZ_Assert(false, "Render API name not found"); - setWindowTitle(QApplication::applicationName()); - } - - setObjectName("MaterialEditorWindow"); - - m_toolBar = new MaterialEditorToolBar(this); - m_toolBar->setObjectName("ToolBar"); - addToolBar(m_toolBar); - - CreateMenu(); - CreateTabBar(); - - m_materialViewport = new MaterialViewportWidget(centralWidget()); - m_materialViewport->setObjectName("Viewport"); - m_materialViewport->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - centralWidget()->layout()->addWidget(m_materialViewport); - - AddDockWidget("Asset Browser", new MaterialBrowserWidget, Qt::BottomDockWidgetArea, Qt::Vertical); - AddDockWidget("Inspector", new MaterialInspector, Qt::RightDockWidgetArea, Qt::Horizontal); - AddDockWidget("Viewport Settings", new ViewportSettingsInspector, Qt::LeftDockWidgetArea, Qt::Horizontal); - AddDockWidget("Performance Monitor", new PerformanceMonitorWidget, Qt::RightDockWidgetArea, Qt::Horizontal); - AddDockWidget("Python Terminal", new AzToolsFramework::CScriptTermDialog, Qt::BottomDockWidgetArea, Qt::Horizontal); - - SetDockWidgetVisible("Viewport Settings", false); - SetDockWidgetVisible("Performance Monitor", false); - SetDockWidgetVisible("Python Terminal", false); - - // Restore geometry and show the window - mainWindowWrapper->showFromSettings(); - - // Restore additional state for docked windows - auto windowSettings = AZ::UserSettings::CreateFind( - AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL); - - if (!windowSettings->m_mainWindowState.empty()) - { - QByteArray windowState(windowSettings->m_mainWindowState.data(), static_cast(windowSettings->m_mainWindowState.size())); - m_advancedDockManager->restoreState(windowState); - } - - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); - OnDocumentOpened(AZ::Uuid::CreateNull()); + AtomToolsDocumentNotificationBus::Handler::BusConnect(); } - MaterialEditorWindow::~MaterialEditorWindow() + AtomToolsDocumentMainWindow::~AtomToolsDocumentMainWindow() { - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); + AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); } - - void MaterialEditorWindow::ResizeViewportRenderTarget(uint32_t width, uint32_t height) - { - QSize requestedViewportSize = QSize(width, height) / devicePixelRatioF(); - QSize currentViewportSize = m_materialViewport->size(); - QSize offset = requestedViewportSize - currentViewportSize; - QSize requestedWindowSize = size() + offset; - resize(requestedWindowSize); - - AZ_Assert( - m_materialViewport->size() == requestedViewportSize, - "Resizing the window did not give the expected viewport size. Requested %d x %d but got %d x %d.", - requestedViewportSize.width(), requestedViewportSize.height(), m_materialViewport->size().width(), - m_materialViewport->size().height()); - - QSize newDeviceSize = m_materialViewport->size(); - AZ_Warning( - "Material Editor", static_cast(newDeviceSize.width()) == width && static_cast(newDeviceSize.height()) == height, - "Resizing the window did not give the expected frame size. Requested %d x %d but got %d x %d.", width, height, - newDeviceSize.width(), newDeviceSize.height()); - } - - void MaterialEditorWindow::LockViewportRenderTargetSize(uint32_t width, uint32_t height) - { - m_materialViewport->LockRenderTargetSize(width, height); - } - - void MaterialEditorWindow::UnlockViewportRenderTargetSize() - { - m_materialViewport->UnlockRenderTargetSize(); - } - - void MaterialEditorWindow::closeEvent(QCloseEvent* closeEvent) + void AtomToolsDocumentMainWindow::closeEvent(QCloseEvent* closeEvent) { bool didClose = true; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); + AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); if (!didClose) { closeEvent->ignore(); return; } - // Capture docking state before shutdown - auto windowSettings = AZ::UserSettings::CreateFind( - AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL); - - QByteArray windowState = m_advancedDockManager->saveState(); - windowSettings->m_mainWindowState.assign(windowState.begin(), windowState.end()); - - AtomToolsFramework::AtomToolsMainWindowNotificationBus::Broadcast( - &AtomToolsFramework::AtomToolsMainWindowNotifications::OnMainWindowClosing); + AtomToolsMainWindowNotificationBus::Broadcast(&AtomToolsMainWindowNotifications::OnMainWindowClosing); } - void MaterialEditorWindow::OnDocumentOpened(const AZ::Uuid& documentId) + void AtomToolsDocumentMainWindow::OnDocumentOpened(const AZ::Uuid& documentId) { bool isOpen = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsOpen); + AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsDocumentRequestBus::Events::IsOpen); bool isSavable = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsSavable); + AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsDocumentRequestBus::Events::IsSavable); bool isModified = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); bool canUndo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo); + AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); bool canRedo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo); + AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); AZStd::string filename; AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); @@ -195,9 +80,9 @@ namespace MaterialEditor contentWidget->setFixedSize(0, 0); return contentWidget; }); - } - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + } const bool hasTabs = m_tabWidget->count() > 0; @@ -220,12 +105,6 @@ namespace MaterialEditor m_actionRedo->setEnabled(canRedo); m_actionSettings->setEnabled(true); - m_actionAssetBrowser->setEnabled(true); - m_actionInspector->setEnabled(true); - m_actionConsole->setEnabled(false); - m_actionPythonTerminal->setEnabled(true); - m_actionPerfMonitor->setEnabled(true); - m_actionViewportSettings->setEnabled(true); m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); m_actionNextTab->setEnabled(m_tabWidget->count() > 1); @@ -241,49 +120,49 @@ namespace MaterialEditor } } - void MaterialEditorWindow::OnDocumentClosed(const AZ::Uuid& documentId) + void AtomToolsDocumentMainWindow::OnDocumentClosed(const AZ::Uuid& documentId) { RemoveTabForDocumentId(documentId); SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); } - void MaterialEditorWindow::OnDocumentModified(const AZ::Uuid& documentId) + void AtomToolsDocumentMainWindow::OnDocumentModified(const AZ::Uuid& documentId) { bool isModified = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); AZStd::string filename; AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); } - void MaterialEditorWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) + void AtomToolsDocumentMainWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) { if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex())) { bool canUndo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo); + AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); bool canRedo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo); + AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); m_actionUndo->setEnabled(canUndo); m_actionRedo->setEnabled(canRedo); } } - void MaterialEditorWindow::OnDocumentSaved(const AZ::Uuid& documentId) + void AtomToolsDocumentMainWindow::OnDocumentSaved(const AZ::Uuid& documentId) { bool isModified = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); AZStd::string filename; AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); } - void MaterialEditorWindow::CreateMenu() + void AtomToolsDocumentMainWindow::CreateMenu() { Base::CreateMenu(); @@ -291,26 +170,26 @@ namespace MaterialEditor m_menuFile = menuBar()->addMenu("&File"); m_actionNew = m_menuFile->addAction("&New...", [this]() { - CreateMaterialDialog createDialog(this); - createDialog.adjustSize(); + //CreateMaterialDialog createDialog(this); + //createDialog.adjustSize(); - if (createDialog.exec() == QDialog::Accepted && - !createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() && - !createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty()) - { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, - createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(), - createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData()); - } + //if (createDialog.exec() == QDialog::Accepted && + // !createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() && + // !createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty()) + //{ + // AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, + // createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(), + // createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData()); + //} }, QKeySequence::New); m_actionOpen = m_menuFile->addAction("&Open...", [this]() { - const AZStd::vector assetTypes = { azrtti_typeid() }; - const AZStd::string filePath = AtomToolsFramework::GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); - if (!filePath.empty()) - { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, filePath); - } + //const AZStd::vector assetTypes = { azrtti_typeid() }; + //const AZStd::string filePath = GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); + //if (!filePath.empty()) + //{ + // AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::OpenDocument, filePath); + //} }, QKeySequence::Open); m_actionOpenRecent = m_menuFile->addAction("Open &Recent"); @@ -320,7 +199,7 @@ namespace MaterialEditor m_actionSave = m_menuFile->addAction("&Save", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); + AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); if (!result) { SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); @@ -332,8 +211,8 @@ namespace MaterialEditor const QString documentPath = GetDocumentPath(documentId); bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy, - documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); + AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy, + documentId, GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); if (!result) { SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); @@ -345,8 +224,8 @@ namespace MaterialEditor const QString documentPath = GetDocumentPath(documentId); bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsChild, - documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); + AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsChild, + documentId, GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); if (!result) { SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); @@ -355,7 +234,7 @@ namespace MaterialEditor m_actionSaveAll = m_menuFile->addAction("Save A&ll", [this]() { bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments); + AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments); if (!result) { SetStatusError(tr("Document save all failed")); @@ -366,16 +245,16 @@ namespace MaterialEditor m_actionClose = m_menuFile->addAction("&Close", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); }, QKeySequence::Close); m_actionCloseAll = m_menuFile->addAction("Close All", [this]() { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); }); m_actionCloseOthers = m_menuFile->addAction("Close Others", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); }); m_menuFile->addSeparator(); @@ -399,7 +278,7 @@ namespace MaterialEditor m_actionUndo = m_menuEdit->addAction("&Undo", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); bool result = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Undo); + AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::Undo); if (!result) { SetStatusError(tr("Document undo failed: %1").arg(GetDocumentPath(documentId))); @@ -409,7 +288,7 @@ namespace MaterialEditor m_actionRedo = m_menuEdit->addAction("&Redo", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); bool result = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Redo); + AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::Redo); if (!result) { SetStatusError(tr("Document redo failed: %1").arg(GetDocumentPath(documentId))); @@ -419,41 +298,13 @@ namespace MaterialEditor m_menuEdit->addSeparator(); m_actionSettings = m_menuEdit->addAction("&Settings...", [this]() { - SettingsDialog dialog(this); - dialog.exec(); + //SettingsDialog dialog(this); + //dialog.exec(); }, QKeySequence::Preferences); m_actionSettings->setEnabled(true); m_menuView = menuBar()->addMenu("&View"); - m_actionAssetBrowser = m_menuView->addAction("&Asset Browser", [this]() { - const AZStd::string label = "Asset Browser"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_actionInspector = m_menuView->addAction("&Inspector", [this]() { - const AZStd::string label = "Inspector"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_actionConsole = m_menuView->addAction("&Console", [this]() { - }); - - m_actionPythonTerminal = m_menuView->addAction("Python &Terminal", [this]() { - const AZStd::string label = "Python Terminal"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_actionPerfMonitor = m_menuView->addAction("Performance &Monitor", [this]() { - const AZStd::string label = "Performance Monitor"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_actionViewportSettings = m_menuView->addAction("Viewport Settings", [this]() { - const AZStd::string label = "Viewport Settings"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - m_menuView->addSeparator(); m_actionPreviousTab = m_menuView->addAction("&Previous Tab", [this]() { @@ -467,15 +318,15 @@ namespace MaterialEditor m_menuHelp = menuBar()->addMenu("&Help"); m_actionHelp = m_menuHelp->addAction("&Help...", [this]() { - HelpDialog dialog(this); - dialog.exec(); + //HelpDialog dialog(this); + //dialog.exec(); }); m_actionAbout = m_menuHelp->addAction("&About...", [this]() { }); } - void MaterialEditorWindow::CreateTabBar() + void AtomToolsDocumentMainWindow::CreateTabBar() { Base::CreateTabBar(); @@ -484,23 +335,23 @@ namespace MaterialEditor // This should automatically clear the active document connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int tabIndex) { const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); + AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); }); connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int tabIndex) { const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); }); } - QString MaterialEditorWindow::GetDocumentPath(const AZ::Uuid& documentId) const + QString AtomToolsDocumentMainWindow::GetDocumentPath(const AZ::Uuid& documentId) const { AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Handler::GetAbsolutePath); + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Handler::GetAbsolutePath); return absolutePath.c_str(); } - void MaterialEditorWindow::OpenTabContextMenu() + void AtomToolsDocumentMainWindow::OpenTabContextMenu() { const QTabBar* tabBar = m_tabWidget->tabBar(); const QPoint position = tabBar->mapFromGlobal(QCursor::pos()); @@ -512,20 +363,20 @@ namespace MaterialEditor const QString selectActionName = (currentTabIndex == clickedTabIndex) ? "Select in Browser" : "Select"; tabMenu.addAction(selectActionName, [this, clickedTabIndex]() { const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); + AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); }); tabMenu.addAction("Close", [this, clickedTabIndex]() { const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); }); auto closeOthersAction = tabMenu.addAction("Close Others", [this, clickedTabIndex]() { const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); }); closeOthersAction->setEnabled(tabBar->count() > 1); tabMenu.exec(QCursor::pos()); } } -} // namespace MaterialEditor +} // namespace AtomToolsFramework -#include +//#include From 62a5c9061622fdce7dbaf799c65c90137153f94f Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 22 Aug 2021 18:02:22 -0500 Subject: [PATCH 20/26] moving document related code from AtomToolsMainWindow to AtomToolsDocumentMainWindow adding virtual function stubs to customize actions Signed-off-by: Guthrie Adams --- .../Document/AtomToolsDocumentMainWindow.h | 39 +- .../Window/AtomToolsMainWindow.h | 21 +- .../Document/AtomToolsDocumentMainWindow.cpp | 447 ++++++++++++------ .../Source/Window/AtomToolsMainWindow.cpp | 144 +----- 4 files changed, 332 insertions(+), 319 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h index 1c8f9a1f55..6beae2a69c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h @@ -12,6 +12,7 @@ #include #include #include +#include #endif namespace AtomToolsFramework @@ -30,7 +31,35 @@ namespace AtomToolsFramework AtomToolsDocumentMainWindow(QWidget* parent = 0); ~AtomToolsDocumentMainWindow(); - private: + protected: + void AddDocumentMenus(); + void AddDocumentTabBar(); + + QString GetDocumentPath(const AZ::Uuid& documentId) const; + + AZ::Uuid GetDocumentIdFromTab(const int tabIndex) const; + + void AddTabForDocumentId( + const AZ::Uuid& documentId, + const AZStd::string& label, + const AZStd::string& toolTip); + + void RemoveTabForDocumentId(const AZ::Uuid& documentId); + + void UpdateTabForDocumentId( + const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified); + + void SelectPreviousTab(); + + void SelectNextTab(); + + virtual void OpenTabContextMenu() const; + virtual bool GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) const; + virtual bool GetOpenFileInfo(AZStd::string& openPath) const; + virtual QWidget* CreateViewForDocumemt(const AZ::Uuid& documentId) const; + virtual void OpenSettings() const; + virtual void OpenHelp() const; + virtual void OpenAbout() const; // AtomToolsDocumentNotificationBus::Handler overrides... void OnDocumentOpened(const AZ::Uuid& documentId) override; @@ -39,13 +68,6 @@ namespace AtomToolsFramework void OnDocumentUndoStateChanged(const AZ::Uuid& documentId) override; void OnDocumentSaved(const AZ::Uuid& documentId) override; - void CreateMenu() override; - void CreateTabBar() override; - - QString GetDocumentPath(const AZ::Uuid& documentId) const; - - void OpenTabContextMenu() override; - void closeEvent(QCloseEvent* closeEvent) override; QMenu* m_menuFile = {}; @@ -73,5 +95,6 @@ namespace AtomToolsFramework QMenu* m_menuHelp = {}; QAction* m_actionHelp = {}; QAction* m_actionAbout = {}; + AzQtComponents::TabWidget* m_tabWidget = {}; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h index 2a304c9a8c..c5b47fe7a4 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h @@ -7,18 +7,14 @@ */ #pragma once + #include - #include - #include #include #include -#include #include -#include -#include namespace AtomToolsFramework { @@ -38,26 +34,11 @@ namespace AtomToolsFramework bool IsDockWidgetVisible(const AZStd::string& name) const override; AZStd::vector GetDockWidgetNames() const override; - virtual void CreateMenu(); - virtual void CreateTabBar(); - - virtual void AddTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, AZStd::function widgetCreator); - virtual void RemoveTabForDocumentId(const AZ::Uuid& documentId); - virtual void UpdateTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified); - virtual AZ::Uuid GetDocumentIdFromTab(const int tabIndex) const; - - virtual void OpenTabContextMenu(); - virtual void SelectPreviousTab(); - virtual void SelectNextTab(); - void SetStatusMessage(const QString& message); void SetStatusWarning(const QString& message); void SetStatusError(const QString& message); AzQtComponents::FancyDocking* m_advancedDockManager = nullptr; - AzQtComponents::TabWidget* m_tabWidget = nullptr; QLabel* m_statusMessage = nullptr; AZStd::unordered_map m_dockWidgets; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp index 502f861f0a..a35b65461a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp @@ -21,6 +21,9 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnin #include #include #include +#include +#include +#include #include AZ_POP_DISABLE_WARNING @@ -30,7 +33,8 @@ namespace AtomToolsFramework : AtomToolsMainWindow(parent) { setObjectName("AtomToolsDocumentMainWindow"); - + AddDocumentMenus(); + AddDocumentTabBar(); AtomToolsDocumentNotificationBus::Handler::BusConnect(); } @@ -39,157 +43,27 @@ namespace AtomToolsFramework AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); } - void AtomToolsDocumentMainWindow::closeEvent(QCloseEvent* closeEvent) + void AtomToolsDocumentMainWindow::AddDocumentMenus() { - bool didClose = true; - AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); - if (!didClose) - { - closeEvent->ignore(); - return; - } - - AtomToolsMainWindowNotificationBus::Broadcast(&AtomToolsMainWindowNotifications::OnMainWindowClosing); - } - - void AtomToolsDocumentMainWindow::OnDocumentOpened(const AZ::Uuid& documentId) - { - bool isOpen = false; - AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsDocumentRequestBus::Events::IsOpen); - bool isSavable = false; - AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsDocumentRequestBus::Events::IsSavable); - bool isModified = false; - AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); - bool canUndo = false; - AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); - bool canRedo = false; - AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); - AZStd::string absolutePath; - AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - - // Update UI to display the new document - if (!documentId.IsNull() && isOpen) - { - // Create a new tab for the document ID and assign it's label to the file name of the document. - AddTabForDocumentId(documentId, filename, absolutePath, [this]{ - // The tab widget requires a dummy page per tab - auto contentWidget = new QWidget(centralWidget()); - contentWidget->setContentsMargins(0, 0, 0, 0); - contentWidget->setFixedSize(0, 0); - return contentWidget; - }); - - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - } - - const bool hasTabs = m_tabWidget->count() > 0; - - // Update menu options - m_actionNew->setEnabled(true); - m_actionOpen->setEnabled(true); - m_actionOpenRecent->setEnabled(false); - m_actionClose->setEnabled(hasTabs); - m_actionCloseAll->setEnabled(hasTabs); - m_actionCloseOthers->setEnabled(hasTabs); - - m_actionSave->setEnabled(isOpen && isSavable); - m_actionSaveAsCopy->setEnabled(isOpen && isSavable); - m_actionSaveAsChild->setEnabled(isOpen); - m_actionSaveAll->setEnabled(hasTabs); - - m_actionExit->setEnabled(true); - - m_actionUndo->setEnabled(canUndo); - m_actionRedo->setEnabled(canRedo); - m_actionSettings->setEnabled(true); - - m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); - m_actionNextTab->setEnabled(m_tabWidget->count() > 1); - - m_actionAbout->setEnabled(false); - - activateWindow(); - raise(); - - const QString documentPath = GetDocumentPath(documentId); - if (!documentPath.isEmpty()) - { - SetStatusMessage(tr("Document opened: %1").arg(documentPath)); - } - } - - void AtomToolsDocumentMainWindow::OnDocumentClosed(const AZ::Uuid& documentId) - { - RemoveTabForDocumentId(documentId); - SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); - } - - void AtomToolsDocumentMainWindow::OnDocumentModified(const AZ::Uuid& documentId) - { - bool isModified = false; - AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); - AZStd::string absolutePath; - AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - } - - void AtomToolsDocumentMainWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) - { - if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex())) - { - bool canUndo = false; - AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); - bool canRedo = false; - AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); - m_actionUndo->setEnabled(canUndo); - m_actionRedo->setEnabled(canRedo); - } - } - - void AtomToolsDocumentMainWindow::OnDocumentSaved(const AZ::Uuid& documentId) - { - bool isModified = false; - AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); - AZStd::string absolutePath; - AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); - } - - void AtomToolsDocumentMainWindow::CreateMenu() - { - Base::CreateMenu(); - // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries m_menuFile = menuBar()->addMenu("&File"); m_actionNew = m_menuFile->addAction("&New...", [this]() { - //CreateMaterialDialog createDialog(this); - //createDialog.adjustSize(); - - //if (createDialog.exec() == QDialog::Accepted && - // !createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() && - // !createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty()) - //{ - // AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, - // createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(), - // createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData()); - //} + AZStd::string openPath; + AZStd::string savePath; + if (GetCreateFileInfo(openPath, savePath)) + { + AtomToolsDocumentSystemRequestBus::Broadcast( + &AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, openPath, savePath); + } }, QKeySequence::New); m_actionOpen = m_menuFile->addAction("&Open...", [this]() { - //const AZStd::vector assetTypes = { azrtti_typeid() }; - //const AZStd::string filePath = GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); - //if (!filePath.empty()) - //{ - // AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::OpenDocument, filePath); - //} + AZStd::string openPath; + if (GetOpenFileInfo(openPath)) + { + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openPath); + } }, QKeySequence::Open); m_actionOpenRecent = m_menuFile->addAction("Open &Recent"); @@ -298,10 +172,8 @@ namespace AtomToolsFramework m_menuEdit->addSeparator(); m_actionSettings = m_menuEdit->addAction("&Settings...", [this]() { - //SettingsDialog dialog(this); - //dialog.exec(); + OpenSettings(); }, QKeySequence::Preferences); - m_actionSettings->setEnabled(true); m_menuView = menuBar()->addMenu("&View"); @@ -318,17 +190,27 @@ namespace AtomToolsFramework m_menuHelp = menuBar()->addMenu("&Help"); m_actionHelp = m_menuHelp->addAction("&Help...", [this]() { - //HelpDialog dialog(this); - //dialog.exec(); + OpenHelp(); }); m_actionAbout = m_menuHelp->addAction("&About...", [this]() { + OpenAbout(); }); } - void AtomToolsDocumentMainWindow::CreateTabBar() + void AtomToolsDocumentMainWindow::AddDocumentTabBar() { - Base::CreateTabBar(); + m_tabWidget = new AzQtComponents::TabWidget(centralWidget()); + m_tabWidget->setObjectName("TabWidget"); + m_tabWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + m_tabWidget->setContentsMargins(0, 0, 0, 0); + + // The tab bar should only be visible if it has active documents + m_tabWidget->setVisible(false); + m_tabWidget->setTabBarAutoHide(false); + m_tabWidget->setMovable(true); + m_tabWidget->setTabsClosable(true); + m_tabWidget->setUsesScrollButtons(true); // This signal will be triggered whenever a tab is added, removed, selected, clicked, dragged // When the last tab is removed tabIndex will be -1 and the document ID will be null @@ -342,6 +224,14 @@ namespace AtomToolsFramework const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); }); + + // Add context menu for right-clicking on tabs + m_tabWidget->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu); + connect(m_tabWidget, &QWidget::customContextMenuRequested, this, [this]() { + OpenTabContextMenu(); + }); + + centralWidget()->layout()->addWidget(m_tabWidget); } QString AtomToolsDocumentMainWindow::GetDocumentPath(const AZ::Uuid& documentId) const @@ -351,7 +241,109 @@ namespace AtomToolsFramework return absolutePath.c_str(); } - void AtomToolsDocumentMainWindow::OpenTabContextMenu() + AZ::Uuid AtomToolsDocumentMainWindow::GetDocumentIdFromTab(const int tabIndex) const + { + const QVariant tabData = m_tabWidget->tabBar()->tabData(tabIndex); + if (!tabData.isNull()) + { + // We need to be able to convert between a UUID and a string to store and retrieve a document ID from the tab bar + const QString documentIdString = tabData.toString(); + const QByteArray documentIdBytes = documentIdString.toUtf8(); + const AZ::Uuid documentId(documentIdBytes.data(), documentIdBytes.size()); + return documentId; + } + return AZ::Uuid::CreateNull(); + } + + void AtomToolsDocumentMainWindow::AddTabForDocumentId( + const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip) + { + // Blocking signals from the tab bar so the currentChanged signal is not sent while a document is already being opened. + // This prevents the OnDocumentOpened notification from being sent recursively. + const QSignalBlocker blocker(m_tabWidget); + + // If a tab for this document already exists then select it instead of creating a new one + for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + { + if (documentId == GetDocumentIdFromTab(tabIndex)) + { + m_tabWidget->setCurrentIndex(tabIndex); + m_tabWidget->repaint(); + return; + } + } + + const int tabIndex = m_tabWidget->addTab(CreateViewForDocumemt(documentId), label.c_str()); + + // The user can manually reorder tabs which will invalidate any association by index. + // We need to store the document ID with the tab using the tab instead of a separate mapping. + m_tabWidget->tabBar()->setTabData(tabIndex, QVariant(documentId.ToString())); + m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); + m_tabWidget->setCurrentIndex(tabIndex); + m_tabWidget->setVisible(true); + m_tabWidget->repaint(); + } + + void AtomToolsDocumentMainWindow::RemoveTabForDocumentId(const AZ::Uuid& documentId) + { + // We are not blocking signals here because we want closing tabs to close the associated document + // and automatically select the next document. + for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + { + if (documentId == GetDocumentIdFromTab(tabIndex)) + { + m_tabWidget->removeTab(tabIndex); + m_tabWidget->setVisible(m_tabWidget->count() > 0); + m_tabWidget->repaint(); + break; + } + } + } + + void AtomToolsDocumentMainWindow::UpdateTabForDocumentId( + const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified) + { + // Whenever a document is opened, saved, or modified we need to update the tab label + if (!documentId.IsNull()) + { + // Because tab order and indexes can change from user interactions, we cannot store a map + // between a tab index and document ID. + // We must iterate over all of the tabs to find the one associated with this document. + for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + { + if (documentId == GetDocumentIdFromTab(tabIndex)) + { + // We use an asterisk prepended to the file name to denote modified document + // Appending is standard and preferred but the tabs elide from the + // end (instead of middle) and cut it off + const AZStd::string modifiedLabel = isModified ? "* " + label : label; + m_tabWidget->setTabText(tabIndex, modifiedLabel.c_str()); + m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); + m_tabWidget->repaint(); + break; + } + } + } + } + + void AtomToolsDocumentMainWindow::SelectPreviousTab() + { + if (m_tabWidget->count() > 1) + { + // Adding count to wrap around when index <= 0 + m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + m_tabWidget->count() - 1) % m_tabWidget->count()); + } + } + + void AtomToolsDocumentMainWindow::SelectNextTab() + { + if (m_tabWidget->count() > 1) + { + m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + 1) % m_tabWidget->count()); + } + } + + void AtomToolsDocumentMainWindow::OpenTabContextMenu() const { const QTabBar* tabBar = m_tabWidget->tabBar(); const QPoint position = tabBar->mapFromGlobal(QCursor::pos()); @@ -377,6 +369,157 @@ namespace AtomToolsFramework tabMenu.exec(QCursor::pos()); } } + + inline bool AtomToolsDocumentMainWindow::GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) const + { + AZ_UNUSED(openPath); + AZ_UNUSED(savePath); + return false; + } + + inline bool AtomToolsDocumentMainWindow::GetOpenFileInfo(AZStd::string& openPath) const + { + AZ_UNUSED(openPath); + return false; + } + + inline QWidget* AtomToolsDocumentMainWindow::CreateViewForDocumemt(const AZ::Uuid& documentId) const + { + AZ_UNUSED(documentId); + auto contentWidget = new QWidget(centralWidget()); + contentWidget->setContentsMargins(0, 0, 0, 0); + contentWidget->setFixedSize(0, 0); + return contentWidget; + } + + inline void AtomToolsDocumentMainWindow::OpenSettings() const + { + } + + inline void AtomToolsDocumentMainWindow::OpenHelp() const + { + } + + inline void AtomToolsDocumentMainWindow::OpenAbout() const + { + } + + void AtomToolsDocumentMainWindow::OnDocumentOpened(const AZ::Uuid& documentId) + { + bool isOpen = false; + AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsDocumentRequestBus::Events::IsOpen); + bool isSavable = false; + AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsDocumentRequestBus::Events::IsSavable); + bool isModified = false; + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); + bool canUndo = false; + AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); + bool canRedo = false; + AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); + AZStd::string absolutePath; + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + + // Update UI to display the new document + if (!documentId.IsNull() && isOpen) + { + // Create a new tab for the document ID and assign it's label to the file name of the document. + AddTabForDocumentId(documentId, filename, absolutePath); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + } + + const bool hasTabs = m_tabWidget->count() > 0; + + // Update menu options + m_actionNew->setEnabled(true); + m_actionOpen->setEnabled(true); + m_actionOpenRecent->setEnabled(false); + m_actionClose->setEnabled(hasTabs); + m_actionCloseAll->setEnabled(hasTabs); + m_actionCloseOthers->setEnabled(hasTabs); + + m_actionSave->setEnabled(isOpen && isSavable); + m_actionSaveAsCopy->setEnabled(isOpen && isSavable); + m_actionSaveAsChild->setEnabled(isOpen); + m_actionSaveAll->setEnabled(hasTabs); + + m_actionExit->setEnabled(true); + + m_actionUndo->setEnabled(canUndo); + m_actionRedo->setEnabled(canRedo); + m_actionSettings->setEnabled(true); + + m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); + m_actionNextTab->setEnabled(m_tabWidget->count() > 1); + + m_actionAbout->setEnabled(false); + + activateWindow(); + raise(); + + const QString documentPath = GetDocumentPath(documentId); + if (!documentPath.isEmpty()) + { + SetStatusMessage(tr("Document opened: %1").arg(documentPath)); + } + } + + void AtomToolsDocumentMainWindow::OnDocumentClosed(const AZ::Uuid& documentId) + { + RemoveTabForDocumentId(documentId); + SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); + } + + void AtomToolsDocumentMainWindow::OnDocumentModified(const AZ::Uuid& documentId) + { + bool isModified = false; + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); + AZStd::string absolutePath; + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + } + + void AtomToolsDocumentMainWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) + { + if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex())) + { + bool canUndo = false; + AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); + bool canRedo = false; + AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); + m_actionUndo->setEnabled(canUndo); + m_actionRedo->setEnabled(canRedo); + } + } + + void AtomToolsDocumentMainWindow::OnDocumentSaved(const AZ::Uuid& documentId) + { + bool isModified = false; + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); + AZStd::string absolutePath; + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); + } + + + void AtomToolsDocumentMainWindow::closeEvent(QCloseEvent* closeEvent) + { + bool didClose = true; + AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); + if (!didClose) + { + closeEvent->ignore(); + return; + } + + AtomToolsMainWindowNotificationBus::Broadcast(&AtomToolsMainWindowNotifications::OnMainWindowClosing); + } } // namespace AtomToolsFramework //#include diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp index cd7d49d8d3..a8ddebfbf0 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include @@ -26,6 +27,10 @@ namespace AtomToolsFramework m_statusMessage = new QLabel(statusBar()); statusBar()->addPermanentWidget(m_statusMessage, 1); + auto menuBar = new QMenuBar(this); + menuBar->setObjectName("MenuBar"); + setMenuBar(menuBar); + auto centralWidget = new QWidget(this); auto centralWidgetLayout = new QVBoxLayout(centralWidget); centralWidgetLayout->setMargin(0); @@ -108,145 +113,6 @@ namespace AtomToolsFramework return names; } - void AtomToolsMainWindow::CreateMenu() - { - auto menuBar = new QMenuBar(this); - menuBar->setObjectName("MenuBar"); - setMenuBar(menuBar); - } - - void AtomToolsMainWindow::CreateTabBar() - { - m_tabWidget = new AzQtComponents::TabWidget(centralWidget()); - m_tabWidget->setObjectName("TabWidget"); - m_tabWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); - m_tabWidget->setContentsMargins(0, 0, 0, 0); - - // The tab bar should only be visible if it has active documents - m_tabWidget->setVisible(false); - m_tabWidget->setTabBarAutoHide(false); - m_tabWidget->setMovable(true); - m_tabWidget->setTabsClosable(true); - m_tabWidget->setUsesScrollButtons(true); - - // Add context menu for right-clicking on tabs - m_tabWidget->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu); - connect( - m_tabWidget, &QWidget::customContextMenuRequested, this, - [this]() - { - OpenTabContextMenu(); - }); - - centralWidget()->layout()->addWidget(m_tabWidget); - } - - void AtomToolsMainWindow::AddTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, AZStd::function widgetCreator) - { - // Blocking signals from the tab bar so the currentChanged signal is not sent while a document is already being opened. - // This prevents the OnDocumentOpened notification from being sent recursively. - const QSignalBlocker blocker(m_tabWidget); - - // If a tab for this document already exists then select it instead of creating a new one - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) - { - if (documentId == GetDocumentIdFromTab(tabIndex)) - { - m_tabWidget->setCurrentIndex(tabIndex); - m_tabWidget->repaint(); - return; - } - } - - const int tabIndex = m_tabWidget->addTab(widgetCreator(), label.c_str()); - - // The user can manually reorder tabs which will invalidate any association by index. - // We need to store the document ID with the tab using the tab instead of a separate mapping. - m_tabWidget->tabBar()->setTabData(tabIndex, QVariant(documentId.ToString())); - m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); - m_tabWidget->setCurrentIndex(tabIndex); - m_tabWidget->setVisible(true); - m_tabWidget->repaint(); - } - - void AtomToolsMainWindow::RemoveTabForDocumentId(const AZ::Uuid& documentId) - { - // We are not blocking signals here because we want closing tabs to close the associated document - // and automatically select the next document. - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) - { - if (documentId == GetDocumentIdFromTab(tabIndex)) - { - m_tabWidget->removeTab(tabIndex); - m_tabWidget->setVisible(m_tabWidget->count() > 0); - m_tabWidget->repaint(); - break; - } - } - } - - void AtomToolsMainWindow::UpdateTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified) - { - // Whenever a document is opened, saved, or modified we need to update the tab label - if (!documentId.IsNull()) - { - // Because tab order and indexes can change from user interactions, we cannot store a map - // between a tab index and document ID. - // We must iterate over all of the tabs to find the one associated with this document. - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) - { - if (documentId == GetDocumentIdFromTab(tabIndex)) - { - // We use an asterisk prepended to the file name to denote modified document - // Appending is standard and preferred but the tabs elide from the - // end (instead of middle) and cut it off - const AZStd::string modifiedLabel = isModified ? "* " + label : label; - m_tabWidget->setTabText(tabIndex, modifiedLabel.c_str()); - m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); - m_tabWidget->repaint(); - break; - } - } - } - } - - AZ::Uuid AtomToolsMainWindow::GetDocumentIdFromTab(const int tabIndex) const - { - const QVariant tabData = m_tabWidget->tabBar()->tabData(tabIndex); - if (!tabData.isNull()) - { - // We need to be able to convert between a UUID and a string to store and retrieve a document ID from the tab bar - const QString documentIdString = tabData.toString(); - const QByteArray documentIdBytes = documentIdString.toUtf8(); - const AZ::Uuid documentId(documentIdBytes.data(), documentIdBytes.size()); - return documentId; - } - return AZ::Uuid::CreateNull(); - } - - void AtomToolsMainWindow::OpenTabContextMenu() - { - } - - void AtomToolsMainWindow::SelectPreviousTab() - { - if (m_tabWidget->count() > 1) - { - // Adding count to wrap around when index <= 0 - m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + m_tabWidget->count() - 1) % m_tabWidget->count()); - } - } - - void AtomToolsMainWindow::SelectNextTab() - { - if (m_tabWidget->count() > 1) - { - m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + 1) % m_tabWidget->count()); - } - } - void AtomToolsMainWindow::SetStatusMessage(const QString& message) { m_statusMessage->setText(QString("%1").arg(message)); From 78f90f2707c836086b719a35fb89910cace165f5 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 22 Aug 2021 22:37:50 -0500 Subject: [PATCH 21/26] updated ME and SMC main window classes to use AtomToolsDocumentMainWindow separated common and document menu creation Signed-off-by: Guthrie Adams --- .../Document/AtomToolsDocumentMainWindow.h | 23 +- .../Window/AtomToolsMainWindow.h | 16 +- .../Document/AtomToolsDocumentMainWindow.cpp | 134 ++---- .../Source/Window/AtomToolsMainWindow.cpp | 56 ++- .../Source/Window/MaterialEditorWindow.cpp | 434 ++---------------- .../Code/Source/Window/MaterialEditorWindow.h | 62 +-- .../Window/ShaderManagementConsoleWindow.cpp | 359 +-------------- .../Window/ShaderManagementConsoleWindow.h | 56 +-- 8 files changed, 204 insertions(+), 936 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h index 6beae2a69c..883a8833ab 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h @@ -53,13 +53,10 @@ namespace AtomToolsFramework void SelectNextTab(); - virtual void OpenTabContextMenu() const; - virtual bool GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) const; - virtual bool GetOpenFileInfo(AZStd::string& openPath) const; - virtual QWidget* CreateViewForDocumemt(const AZ::Uuid& documentId) const; - virtual void OpenSettings() const; - virtual void OpenHelp() const; - virtual void OpenAbout() const; + virtual void OpenTabContextMenu(); + virtual bool GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath); + virtual bool GetOpenFileInfo(AZStd::string& openPath); + virtual QWidget* CreateViewForDocumemt(const AZ::Uuid& documentId); // AtomToolsDocumentNotificationBus::Handler overrides... void OnDocumentOpened(const AZ::Uuid& documentId) override; @@ -70,10 +67,11 @@ namespace AtomToolsFramework void closeEvent(QCloseEvent* closeEvent) override; - QMenu* m_menuFile = {}; + template + QAction* CreateAction(const QString& text, Functor functor, const QKeySequence& shortcut = 0); + QAction* m_actionNew = {}; QAction* m_actionOpen = {}; - QAction* m_actionOpenRecent = {}; QAction* m_actionClose = {}; QAction* m_actionCloseAll = {}; QAction* m_actionCloseOthers = {}; @@ -81,20 +79,13 @@ namespace AtomToolsFramework QAction* m_actionSaveAsCopy = {}; QAction* m_actionSaveAsChild = {}; QAction* m_actionSaveAll = {}; - QAction* m_actionExit = {}; - QMenu* m_menuEdit = {}; QAction* m_actionUndo = {}; QAction* m_actionRedo = {}; - QAction* m_actionSettings = {}; - QMenu* m_menuView = {}; QAction* m_actionNextTab = {}; QAction* m_actionPreviousTab = {}; - QMenu* m_menuHelp = {}; - QAction* m_actionHelp = {}; - QAction* m_actionAbout = {}; AzQtComponents::TabWidget* m_tabWidget = {}; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h index c5b47fe7a4..8d30e42bbb 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h @@ -38,8 +38,20 @@ namespace AtomToolsFramework void SetStatusWarning(const QString& message); void SetStatusError(const QString& message); - AzQtComponents::FancyDocking* m_advancedDockManager = nullptr; - QLabel* m_statusMessage = nullptr; + void AddCommonMenus(); + + virtual void OpenSettings(); + virtual void OpenHelp(); + virtual void OpenAbout(); + + AzQtComponents::FancyDocking* m_advancedDockManager = {}; + + QLabel* m_statusMessage = {}; + + QMenu* m_menuFile = {}; + QMenu* m_menuEdit = {}; + QMenu* m_menuView = {}; + QMenu* m_menuHelp = {}; AZStd::unordered_map m_dockWidgets; }; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp index a35b65461a..4e7bc8edbd 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp @@ -12,15 +12,11 @@ #include #include #include -#include -#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include #include #include -#include -#include #include #include #include @@ -45,10 +41,10 @@ namespace AtomToolsFramework void AtomToolsDocumentMainWindow::AddDocumentMenus() { - // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries - m_menuFile = menuBar()->addMenu("&File"); + QAction* insertPostion = !m_menuFile->actions().empty() ? m_menuFile->actions().front() : nullptr; - m_actionNew = m_menuFile->addAction("&New...", [this]() { + // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries + m_actionNew = CreateAction("&New...", [this]() { AZStd::string openPath; AZStd::string savePath; if (GetCreateFileInfo(openPath, savePath)) @@ -57,20 +53,19 @@ namespace AtomToolsFramework &AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, openPath, savePath); } }, QKeySequence::New); + m_menuFile->insertAction(insertPostion, m_actionNew); - m_actionOpen = m_menuFile->addAction("&Open...", [this]() { + m_actionOpen = CreateAction("&Open...", [this]() { AZStd::string openPath; if (GetOpenFileInfo(openPath)) { AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openPath); } }, QKeySequence::Open); + m_menuFile->insertAction(insertPostion, m_actionOpen); + m_menuFile->insertSeparator(insertPostion); - m_actionOpenRecent = m_menuFile->addAction("Open &Recent"); - - m_menuFile->addSeparator(); - - m_actionSave = m_menuFile->addAction("&Save", [this]() { + m_actionSave = CreateAction("&Save", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); bool result = false; AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); @@ -79,8 +74,9 @@ namespace AtomToolsFramework SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::Save); + m_menuFile->insertAction(insertPostion, m_actionSave); - m_actionSaveAsCopy = m_menuFile->addAction("Save &As...", [this]() { + m_actionSaveAsCopy = CreateAction("Save &As...", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); const QString documentPath = GetDocumentPath(documentId); @@ -92,8 +88,9 @@ namespace AtomToolsFramework SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::SaveAs); + m_menuFile->insertAction(insertPostion, m_actionSaveAsCopy); - m_actionSaveAsChild = m_menuFile->addAction("Save As &Child...", [this]() { + m_actionSaveAsChild = CreateAction("Save As &Child...", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); const QString documentPath = GetDocumentPath(documentId); @@ -105,8 +102,9 @@ namespace AtomToolsFramework SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); } }); + m_menuFile->insertAction(insertPostion, m_actionSaveAsChild); - m_actionSaveAll = m_menuFile->addAction("Save A&ll", [this]() { + m_actionSaveAll = CreateAction("Save A&ll", [this]() { bool result = false; AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments); if (!result) @@ -114,42 +112,30 @@ namespace AtomToolsFramework SetStatusError(tr("Document save all failed")); } }); + m_menuFile->insertAction(insertPostion, m_actionSaveAll); + m_menuFile->insertSeparator(insertPostion); - m_menuFile->addSeparator(); - - m_actionClose = m_menuFile->addAction("&Close", [this]() { + m_actionClose = CreateAction("&Close", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); }, QKeySequence::Close); + m_menuFile->insertAction(insertPostion, m_actionClose); - m_actionCloseAll = m_menuFile->addAction("Close All", [this]() { + m_actionCloseAll = CreateAction("Close All", [this]() { AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); }); + m_menuFile->insertAction(insertPostion, m_actionCloseAll); - m_actionCloseOthers = m_menuFile->addAction("Close Others", [this]() { + m_actionCloseOthers = CreateAction("Close Others", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); }); + m_menuFile->insertAction(insertPostion, m_actionCloseOthers); + m_menuFile->insertSeparator(insertPostion); - m_menuFile->addSeparator(); + insertPostion = !m_menuEdit->actions().empty() ? m_menuEdit->actions().front() : nullptr; - m_menuFile->addAction("Run &Python...", [this]() { - const QString script = QFileDialog::getOpenFileName(this, "Run Script", QString(), QString("*.py")); - if (!script.isEmpty()) - { - AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilename, script.toUtf8().constData()); - } - }); - - m_menuFile->addSeparator(); - - m_actionExit = m_menuFile->addAction("E&xit", [this]() { - close(); - }, QKeySequence::Quit); - - m_menuEdit = menuBar()->addMenu("&Edit"); - - m_actionUndo = m_menuEdit->addAction("&Undo", [this]() { + m_actionUndo = CreateAction("&Undo", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); bool result = false; AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::Undo); @@ -158,8 +144,9 @@ namespace AtomToolsFramework SetStatusError(tr("Document undo failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::Undo); + m_menuEdit->insertAction(insertPostion, m_actionUndo); - m_actionRedo = m_menuEdit->addAction("&Redo", [this]() { + m_actionRedo = CreateAction("&Redo", [this]() { const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); bool result = false; AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::Redo); @@ -168,34 +155,24 @@ namespace AtomToolsFramework SetStatusError(tr("Document redo failed: %1").arg(GetDocumentPath(documentId))); } }, QKeySequence::Redo); + m_menuEdit->insertAction(insertPostion, m_actionRedo); + m_menuEdit->insertSeparator(insertPostion); - m_menuEdit->addSeparator(); + insertPostion = !m_menuView->actions().empty() ? m_menuView->actions().front() : nullptr; - m_actionSettings = m_menuEdit->addAction("&Settings...", [this]() { - OpenSettings(); - }, QKeySequence::Preferences); - - m_menuView = menuBar()->addMenu("&View"); - - m_menuView->addSeparator(); - - m_actionPreviousTab = m_menuView->addAction("&Previous Tab", [this]() { + m_actionPreviousTab = CreateAction( + "&Previous Tab", + [this]() + { SelectPreviousTab(); }, Qt::CTRL | Qt::SHIFT | Qt::Key_Tab); //QKeySequence::PreviousChild is mapped incorrectly in Qt + m_menuView->insertAction(insertPostion, m_actionPreviousTab); - m_actionNextTab = m_menuView->addAction("&Next Tab", [this]() { + m_actionNextTab = CreateAction("&Next Tab", [this]() { SelectNextTab(); }, Qt::CTRL | Qt::Key_Tab); //QKeySequence::NextChild works as expected but mirroring Previous - - m_menuHelp = menuBar()->addMenu("&Help"); - - m_actionHelp = m_menuHelp->addAction("&Help...", [this]() { - OpenHelp(); - }); - - m_actionAbout = m_menuHelp->addAction("&About...", [this]() { - OpenAbout(); - }); + m_menuView->insertAction(insertPostion, m_actionNextTab); + m_menuView->insertSeparator(insertPostion); } void AtomToolsDocumentMainWindow::AddDocumentTabBar() @@ -343,7 +320,7 @@ namespace AtomToolsFramework } } - void AtomToolsDocumentMainWindow::OpenTabContextMenu() const + void AtomToolsDocumentMainWindow::OpenTabContextMenu() { const QTabBar* tabBar = m_tabWidget->tabBar(); const QPoint position = tabBar->mapFromGlobal(QCursor::pos()); @@ -370,20 +347,20 @@ namespace AtomToolsFramework } } - inline bool AtomToolsDocumentMainWindow::GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) const + inline bool AtomToolsDocumentMainWindow::GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) { AZ_UNUSED(openPath); AZ_UNUSED(savePath); return false; } - inline bool AtomToolsDocumentMainWindow::GetOpenFileInfo(AZStd::string& openPath) const + inline bool AtomToolsDocumentMainWindow::GetOpenFileInfo(AZStd::string& openPath) { AZ_UNUSED(openPath); return false; } - inline QWidget* AtomToolsDocumentMainWindow::CreateViewForDocumemt(const AZ::Uuid& documentId) const + inline QWidget* AtomToolsDocumentMainWindow::CreateViewForDocumemt(const AZ::Uuid& documentId) { AZ_UNUSED(documentId); auto contentWidget = new QWidget(centralWidget()); @@ -392,18 +369,6 @@ namespace AtomToolsFramework return contentWidget; } - inline void AtomToolsDocumentMainWindow::OpenSettings() const - { - } - - inline void AtomToolsDocumentMainWindow::OpenHelp() const - { - } - - inline void AtomToolsDocumentMainWindow::OpenAbout() const - { - } - void AtomToolsDocumentMainWindow::OnDocumentOpened(const AZ::Uuid& documentId) { bool isOpen = false; @@ -434,7 +399,6 @@ namespace AtomToolsFramework // Update menu options m_actionNew->setEnabled(true); m_actionOpen->setEnabled(true); - m_actionOpenRecent->setEnabled(false); m_actionClose->setEnabled(hasTabs); m_actionCloseAll->setEnabled(hasTabs); m_actionCloseOthers->setEnabled(hasTabs); @@ -444,17 +408,12 @@ namespace AtomToolsFramework m_actionSaveAsChild->setEnabled(isOpen); m_actionSaveAll->setEnabled(hasTabs); - m_actionExit->setEnabled(true); - m_actionUndo->setEnabled(canUndo); m_actionRedo->setEnabled(canRedo); - m_actionSettings->setEnabled(true); m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); m_actionNextTab->setEnabled(m_tabWidget->count() > 1); - m_actionAbout->setEnabled(false); - activateWindow(); raise(); @@ -520,6 +479,15 @@ namespace AtomToolsFramework AtomToolsMainWindowNotificationBus::Broadcast(&AtomToolsMainWindowNotifications::OnMainWindowClosing); } + + template + QAction* AtomToolsDocumentMainWindow::CreateAction(const QString& text, Functor functor, const QKeySequence& shortcut) + { + QAction* action = new QAction(text, this); + action->setShortcut(shortcut); + connect(action, &QAction::triggered, this, functor); + return action; + } } // namespace AtomToolsFramework //#include diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp index a8ddebfbf0..e586dbc588 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp @@ -7,6 +7,10 @@ */ #include +#include + +#include +#include #include #include #include @@ -24,13 +28,11 @@ namespace AtomToolsFramework setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); + AddCommonMenus(); + m_statusMessage = new QLabel(statusBar()); statusBar()->addPermanentWidget(m_statusMessage, 1); - auto menuBar = new QMenuBar(this); - menuBar->setObjectName("MenuBar"); - setMenuBar(menuBar); - auto centralWidget = new QWidget(this); auto centralWidgetLayout = new QVBoxLayout(centralWidget); centralWidgetLayout->setMargin(0); @@ -127,4 +129,50 @@ namespace AtomToolsFramework { m_statusMessage->setText(QString("%1").arg(message)); } + + void AtomToolsMainWindow::AddCommonMenus() + { + m_menuFile = menuBar()->addMenu("&File"); + m_menuEdit = menuBar()->addMenu("&Edit"); + m_menuView = menuBar()->addMenu("&View"); + m_menuHelp = menuBar()->addMenu("&Help"); + + m_menuFile->addAction("Run &Python...", [this]() { + const QString script = QFileDialog::getOpenFileName(this, "Run Script", QString(), QString("*.py")); + if (!script.isEmpty()) + { + AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilename, script.toUtf8().constData()); + } + }); + + m_menuFile->addSeparator(); + + m_menuFile->addAction("E&xit", [this]() { + close(); + }, QKeySequence::Quit); + + m_menuEdit->addAction("&Settings...", [this]() { + OpenSettings(); + }, QKeySequence::Preferences); + + m_menuHelp->addAction("&Help...", [this]() { + OpenHelp(); + }); + + m_menuHelp->addAction("&About...", [this]() { + OpenAbout(); + }); + } + + void AtomToolsMainWindow::OpenSettings() + { + } + + void AtomToolsMainWindow::OpenHelp() + { + } + + void AtomToolsMainWindow::OpenAbout() + { + } } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp index 8922591580..5f895ba804 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp @@ -9,15 +9,9 @@ #include #include #include -#include -#include #include -#include -#include #include #include -#include -#include #include #include #include @@ -33,7 +27,6 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnin #include #include #include -#include #include #include AZ_POP_DISABLE_WARNING @@ -41,7 +34,7 @@ AZ_POP_DISABLE_WARNING namespace MaterialEditor { MaterialEditorWindow::MaterialEditorWindow(QWidget* parent /* = 0 */) - : AtomToolsFramework::AtomToolsMainWindow(parent) + : AtomToolsFramework::AtomToolsDocumentMainWindow(parent) { resize(1280, 1024); @@ -74,9 +67,6 @@ namespace MaterialEditor m_toolBar->setObjectName("ToolBar"); addToolBar(m_toolBar); - CreateMenu(); - CreateTabBar(); - m_materialViewport = new MaterialViewportWidget(centralWidget()); m_materialViewport->setObjectName("Viewport"); m_materialViewport->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); @@ -105,15 +95,12 @@ namespace MaterialEditor m_advancedDockManager->restoreState(windowState); } - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); OnDocumentOpened(AZ::Uuid::CreateNull()); } MaterialEditorWindow::~MaterialEditorWindow() { - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); } - void MaterialEditorWindow::ResizeViewportRenderTarget(uint32_t width, uint32_t height) { @@ -146,16 +133,56 @@ namespace MaterialEditor m_materialViewport->UnlockRenderTargetSize(); } + bool MaterialEditorWindow::GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) + { + CreateMaterialDialog createDialog(this); + createDialog.adjustSize(); + + if (createDialog.exec() == QDialog::Accepted && + !createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() && + !createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty()) + { + savePath = createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData(); + openPath = createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(); + return true; + } + return false; + } + + bool MaterialEditorWindow::GetOpenFileInfo(AZStd::string& openPath) + { + const AZStd::vector assetTypes = { azrtti_typeid() }; + openPath = AtomToolsFramework::GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); + return !openPath.empty(); + } + + QWidget* MaterialEditorWindow::CreateViewForDocumemt(const AZ::Uuid& documentId) + { + AZ_UNUSED(documentId); + auto contentWidget = new QWidget(centralWidget()); + contentWidget->setContentsMargins(0, 0, 0, 0); + contentWidget->setFixedSize(0, 0); + return contentWidget; + } + + void MaterialEditorWindow::OpenSettings() + { + SettingsDialog dialog(this); + dialog.exec(); + } + + void MaterialEditorWindow::OpenHelp() + { + HelpDialog dialog(this); + dialog.exec(); + } + + void MaterialEditorWindow::OpenAbout() + { + } + void MaterialEditorWindow::closeEvent(QCloseEvent* closeEvent) { - bool didClose = true; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); - if (!didClose) - { - closeEvent->ignore(); - return; - } - // Capture docking state before shutdown auto windowSettings = AZ::UserSettings::CreateFind( AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL); @@ -163,368 +190,7 @@ namespace MaterialEditor QByteArray windowState = m_advancedDockManager->saveState(); windowSettings->m_mainWindowState.assign(windowState.begin(), windowState.end()); - AtomToolsFramework::AtomToolsMainWindowNotificationBus::Broadcast( - &AtomToolsFramework::AtomToolsMainWindowNotifications::OnMainWindowClosing); - } - - void MaterialEditorWindow::OnDocumentOpened(const AZ::Uuid& documentId) - { - bool isOpen = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsOpen); - bool isSavable = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsSavable); - bool isModified = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); - bool canUndo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo); - bool canRedo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo); - AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - - // Update UI to display the new document - if (!documentId.IsNull() && isOpen) - { - // Create a new tab for the document ID and assign it's label to the file name of the document. - AddTabForDocumentId(documentId, filename, absolutePath, [this]{ - // The tab widget requires a dummy page per tab - auto contentWidget = new QWidget(centralWidget()); - contentWidget->setContentsMargins(0, 0, 0, 0); - contentWidget->setFixedSize(0, 0); - return contentWidget; - }); - } - - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - - const bool hasTabs = m_tabWidget->count() > 0; - - // Update menu options - m_actionNew->setEnabled(true); - m_actionOpen->setEnabled(true); - m_actionOpenRecent->setEnabled(false); - m_actionClose->setEnabled(hasTabs); - m_actionCloseAll->setEnabled(hasTabs); - m_actionCloseOthers->setEnabled(hasTabs); - - m_actionSave->setEnabled(isOpen && isSavable); - m_actionSaveAsCopy->setEnabled(isOpen && isSavable); - m_actionSaveAsChild->setEnabled(isOpen); - m_actionSaveAll->setEnabled(hasTabs); - - m_actionExit->setEnabled(true); - - m_actionUndo->setEnabled(canUndo); - m_actionRedo->setEnabled(canRedo); - m_actionSettings->setEnabled(true); - - m_actionAssetBrowser->setEnabled(true); - m_actionInspector->setEnabled(true); - m_actionConsole->setEnabled(false); - m_actionPythonTerminal->setEnabled(true); - m_actionPerfMonitor->setEnabled(true); - m_actionViewportSettings->setEnabled(true); - m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); - m_actionNextTab->setEnabled(m_tabWidget->count() > 1); - - m_actionAbout->setEnabled(false); - - activateWindow(); - raise(); - - const QString documentPath = GetDocumentPath(documentId); - if (!documentPath.isEmpty()) - { - SetStatusMessage(tr("Document opened: %1").arg(documentPath)); - } - } - - void MaterialEditorWindow::OnDocumentClosed(const AZ::Uuid& documentId) - { - RemoveTabForDocumentId(documentId); - SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); - } - - void MaterialEditorWindow::OnDocumentModified(const AZ::Uuid& documentId) - { - bool isModified = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); - AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - } - - void MaterialEditorWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) - { - if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex())) - { - bool canUndo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo); - bool canRedo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo); - m_actionUndo->setEnabled(canUndo); - m_actionRedo->setEnabled(canRedo); - } - } - - void MaterialEditorWindow::OnDocumentSaved(const AZ::Uuid& documentId) - { - bool isModified = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); - AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); - } - - void MaterialEditorWindow::CreateMenu() - { - Base::CreateMenu(); - - // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries - m_menuFile = menuBar()->addMenu("&File"); - - m_actionNew = m_menuFile->addAction("&New...", [this]() { - CreateMaterialDialog createDialog(this); - createDialog.adjustSize(); - - if (createDialog.exec() == QDialog::Accepted && - !createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() && - !createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty()) - { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, - createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(), - createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData()); - } - }, QKeySequence::New); - - m_actionOpen = m_menuFile->addAction("&Open...", [this]() { - const AZStd::vector assetTypes = { azrtti_typeid() }; - const AZStd::string filePath = AtomToolsFramework::GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); - if (!filePath.empty()) - { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, filePath); - } - }, QKeySequence::Open); - - m_actionOpenRecent = m_menuFile->addAction("Open &Recent"); - - m_menuFile->addSeparator(); - - m_actionSave = m_menuFile->addAction("&Save", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); - if (!result) - { - SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); - } - }, QKeySequence::Save); - - m_actionSaveAsCopy = m_menuFile->addAction("Save &As...", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - const QString documentPath = GetDocumentPath(documentId); - - bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy, - documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); - if (!result) - { - SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); - } - }, QKeySequence::SaveAs); - - m_actionSaveAsChild = m_menuFile->addAction("Save As &Child...", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - const QString documentPath = GetDocumentPath(documentId); - - bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsChild, - documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); - if (!result) - { - SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); - } - }); - - m_actionSaveAll = m_menuFile->addAction("Save A&ll", [this]() { - bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments); - if (!result) - { - SetStatusError(tr("Document save all failed")); - } - }); - - m_menuFile->addSeparator(); - - m_actionClose = m_menuFile->addAction("&Close", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); - }, QKeySequence::Close); - - m_actionCloseAll = m_menuFile->addAction("Close All", [this]() { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); - }); - - m_actionCloseOthers = m_menuFile->addAction("Close Others", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); - }); - - m_menuFile->addSeparator(); - - m_menuFile->addAction("Run &Python...", [this]() { - const QString script = QFileDialog::getOpenFileName(this, "Run Script", QString(), QString("*.py")); - if (!script.isEmpty()) - { - AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilename, script.toUtf8().constData()); - } - }); - - m_menuFile->addSeparator(); - - m_actionExit = m_menuFile->addAction("E&xit", [this]() { - close(); - }, QKeySequence::Quit); - - m_menuEdit = menuBar()->addMenu("&Edit"); - - m_actionUndo = m_menuEdit->addAction("&Undo", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - bool result = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Undo); - if (!result) - { - SetStatusError(tr("Document undo failed: %1").arg(GetDocumentPath(documentId))); - } - }, QKeySequence::Undo); - - m_actionRedo = m_menuEdit->addAction("&Redo", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - bool result = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Redo); - if (!result) - { - SetStatusError(tr("Document redo failed: %1").arg(GetDocumentPath(documentId))); - } - }, QKeySequence::Redo); - - m_menuEdit->addSeparator(); - - m_actionSettings = m_menuEdit->addAction("&Settings...", [this]() { - SettingsDialog dialog(this); - dialog.exec(); - }, QKeySequence::Preferences); - m_actionSettings->setEnabled(true); - - m_menuView = menuBar()->addMenu("&View"); - - m_actionAssetBrowser = m_menuView->addAction("&Asset Browser", [this]() { - const AZStd::string label = "Asset Browser"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_actionInspector = m_menuView->addAction("&Inspector", [this]() { - const AZStd::string label = "Inspector"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_actionConsole = m_menuView->addAction("&Console", [this]() { - }); - - m_actionPythonTerminal = m_menuView->addAction("Python &Terminal", [this]() { - const AZStd::string label = "Python Terminal"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_actionPerfMonitor = m_menuView->addAction("Performance &Monitor", [this]() { - const AZStd::string label = "Performance Monitor"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_actionViewportSettings = m_menuView->addAction("Viewport Settings", [this]() { - const AZStd::string label = "Viewport Settings"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_menuView->addSeparator(); - - m_actionPreviousTab = m_menuView->addAction("&Previous Tab", [this]() { - SelectPreviousTab(); - }, Qt::CTRL | Qt::SHIFT | Qt::Key_Tab); //QKeySequence::PreviousChild is mapped incorrectly in Qt - - m_actionNextTab = m_menuView->addAction("&Next Tab", [this]() { - SelectNextTab(); - }, Qt::CTRL | Qt::Key_Tab); //QKeySequence::NextChild works as expected but mirroring Previous - - m_menuHelp = menuBar()->addMenu("&Help"); - - m_actionHelp = m_menuHelp->addAction("&Help...", [this]() { - HelpDialog dialog(this); - dialog.exec(); - }); - - m_actionAbout = m_menuHelp->addAction("&About...", [this]() { - }); - } - - void MaterialEditorWindow::CreateTabBar() - { - Base::CreateTabBar(); - - // This signal will be triggered whenever a tab is added, removed, selected, clicked, dragged - // When the last tab is removed tabIndex will be -1 and the document ID will be null - // This should automatically clear the active document - connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int tabIndex) { - const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); - }); - - connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int tabIndex) { - const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); - }); - } - - QString MaterialEditorWindow::GetDocumentPath(const AZ::Uuid& documentId) const - { - AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Handler::GetAbsolutePath); - return absolutePath.c_str(); - } - - void MaterialEditorWindow::OpenTabContextMenu() - { - const QTabBar* tabBar = m_tabWidget->tabBar(); - const QPoint position = tabBar->mapFromGlobal(QCursor::pos()); - const int clickedTabIndex = tabBar->tabAt(position); - const int currentTabIndex = tabBar->currentIndex(); - if (clickedTabIndex >= 0) - { - QMenu tabMenu; - const QString selectActionName = (currentTabIndex == clickedTabIndex) ? "Select in Browser" : "Select"; - tabMenu.addAction(selectActionName, [this, clickedTabIndex]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); - }); - tabMenu.addAction("Close", [this, clickedTabIndex]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); - }); - auto closeOthersAction = tabMenu.addAction("Close Others", [this, clickedTabIndex]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); - }); - closeOthersAction->setEnabled(tabBar->count() > 1); - tabMenu.exec(QCursor::pos()); - } + Base::closeEvent(closeEvent); } } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h index b7d0cbf8da..72fd525fce 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h @@ -9,9 +9,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include -#include -#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include @@ -29,72 +27,32 @@ namespace MaterialEditor * 3) MaterialPropertyInspector - The user edits the properties of the selected Material. */ class MaterialEditorWindow - : public AtomToolsFramework::AtomToolsMainWindow - , private AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler + : public AtomToolsFramework::AtomToolsDocumentMainWindow { Q_OBJECT public: AZ_CLASS_ALLOCATOR(MaterialEditorWindow, AZ::SystemAllocator, 0); - using Base = AtomToolsFramework::AtomToolsMainWindow; + using Base = AtomToolsFramework::AtomToolsDocumentMainWindow; MaterialEditorWindow(QWidget* parent = 0); ~MaterialEditorWindow(); - private: + protected: void ResizeViewportRenderTarget(uint32_t width, uint32_t height) override; void LockViewportRenderTargetSize(uint32_t width, uint32_t height) override; void UnlockViewportRenderTargetSize() override; - // AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler overrides... - void OnDocumentOpened(const AZ::Uuid& documentId) override; - void OnDocumentClosed(const AZ::Uuid& documentId) override; - void OnDocumentModified(const AZ::Uuid& documentId) override; - void OnDocumentUndoStateChanged(const AZ::Uuid& documentId) override; - void OnDocumentSaved(const AZ::Uuid& documentId) override; - - void CreateMenu() override; - void CreateTabBar() override; - - QString GetDocumentPath(const AZ::Uuid& documentId) const; - - void OpenTabContextMenu() override; + bool GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) override; + bool GetOpenFileInfo(AZStd::string& openPath) override; + QWidget* CreateViewForDocumemt(const AZ::Uuid& documentId) override; + void OpenSettings() override; + void OpenHelp() override; + void OpenAbout() override; void closeEvent(QCloseEvent* closeEvent) override; MaterialViewportWidget* m_materialViewport = nullptr; MaterialEditorToolBar* m_toolBar = nullptr; - - QMenu* m_menuFile = {}; - QAction* m_actionNew = {}; - QAction* m_actionOpen = {}; - QAction* m_actionOpenRecent = {}; - QAction* m_actionClose = {}; - QAction* m_actionCloseAll = {}; - QAction* m_actionCloseOthers = {}; - QAction* m_actionSave = {}; - QAction* m_actionSaveAsCopy = {}; - QAction* m_actionSaveAsChild = {}; - QAction* m_actionSaveAll = {}; - QAction* m_actionExit = {}; - - QMenu* m_menuEdit = {}; - QAction* m_actionUndo = {}; - QAction* m_actionRedo = {}; - QAction* m_actionSettings = {}; - - QMenu* m_menuView = {}; - QAction* m_actionAssetBrowser = {}; - QAction* m_actionInspector = {}; - QAction* m_actionConsole = {}; - QAction* m_actionPythonTerminal = {}; - QAction* m_actionPerfMonitor = {}; - QAction* m_actionViewportSettings = {}; - QAction* m_actionNextTab = {}; - QAction* m_actionPreviousTab = {}; - - QMenu* m_menuHelp = {}; - QAction* m_actionHelp = {}; - QAction* m_actionAbout = {}; }; } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp index 6354f8beba..e44101c300 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp @@ -7,22 +7,13 @@ */ #include -#include -#include #include -#include -#include #include #include -#include #include -#include -#include #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include #include #include #include @@ -32,7 +23,7 @@ AZ_POP_DISABLE_WARNING namespace ShaderManagementConsole { ShaderManagementConsoleWindow::ShaderManagementConsoleWindow(QWidget* parent /* = 0 */) - : AtomToolsFramework::AtomToolsMainWindow(parent) + : AtomToolsFramework::AtomToolsDocumentMainWindow(parent) { resize(1280, 1024); @@ -50,9 +41,6 @@ namespace ShaderManagementConsole m_toolBar->setObjectName("ToolBar"); addToolBar(m_toolBar); - CreateMenu(); - CreateTabBar(); - AddDockWidget("Asset Browser", new ShaderManagementConsoleBrowserWidget, Qt::BottomDockWidgetArea, Qt::Vertical); AddDockWidget("Python Terminal", new AzToolsFramework::CScriptTermDialog, Qt::BottomDockWidgetArea, Qt::Horizontal); @@ -61,356 +49,34 @@ namespace ShaderManagementConsole // Restore geometry and show the window mainWindowWrapper->showFromSettings(); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); OnDocumentOpened(AZ::Uuid::CreateNull()); } ShaderManagementConsoleWindow::~ShaderManagementConsoleWindow() { - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); } - void ShaderManagementConsoleWindow::closeEvent(QCloseEvent* closeEvent) - { - bool didClose = true; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); - if (!didClose) - { - closeEvent->ignore(); - return; - } - - AtomToolsFramework::AtomToolsMainWindowNotificationBus::Broadcast( - &AtomToolsFramework::AtomToolsMainWindowNotifications::OnMainWindowClosing); - } - - void ShaderManagementConsoleWindow::OnDocumentOpened(const AZ::Uuid& documentId) - { - bool isOpen = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsOpen); - bool isSavable = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsSavable); - bool isModified = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); - bool canUndo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo); - bool canRedo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo); - AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - - // Update UI to display the new document - if (!documentId.IsNull() && isOpen) - { - // Create a new tab for the document ID and assign it's label to the file name of the document. - AddTabForDocumentId(documentId, filename, absolutePath, [this, documentId]{ - // The document tab contains a table view. - auto contentWidget = new QTableView(centralWidget()); - contentWidget->setSelectionBehavior(QAbstractItemView::SelectRows); - contentWidget->setModel(CreateDocumentContent(documentId)); - return contentWidget; - }); - } - - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - - const bool hasTabs = m_tabWidget->count() > 0; - - // Update menu options - m_actionOpen->setEnabled(true); - m_actionOpenRecent->setEnabled(false); - m_actionClose->setEnabled(hasTabs); - m_actionCloseAll->setEnabled(hasTabs); - m_actionCloseOthers->setEnabled(hasTabs); - - m_actionSave->setEnabled(isOpen && isSavable); - m_actionSaveAsCopy->setEnabled(isOpen && isSavable); - m_actionSaveAll->setEnabled(hasTabs); - - m_actionExit->setEnabled(true); - - m_actionUndo->setEnabled(canUndo); - m_actionRedo->setEnabled(canRedo); - m_actionSettings->setEnabled(false); - - m_actionAssetBrowser->setEnabled(true); - m_actionPythonTerminal->setEnabled(true); - m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); - m_actionNextTab->setEnabled(m_tabWidget->count() > 1); - - m_actionHelp->setEnabled(false); - m_actionAbout->setEnabled(false); - - activateWindow(); - raise(); - - const QString documentPath = GetDocumentPath(documentId); - if (!documentPath.isEmpty()) - { - SetStatusMessage(tr("Document opened: %1").arg(documentPath)); - } - } - - void ShaderManagementConsoleWindow::OnDocumentClosed(const AZ::Uuid& documentId) - { - RemoveTabForDocumentId(documentId); - SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); - } - - void ShaderManagementConsoleWindow::OnDocumentModified(const AZ::Uuid& documentId) - { - bool isModified = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); - AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - } - - void ShaderManagementConsoleWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) - { - if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex())) - { - bool canUndo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo); - bool canRedo = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo); - m_actionUndo->setEnabled(canUndo); - m_actionRedo->setEnabled(canRedo); - } - } - - void ShaderManagementConsoleWindow::OnDocumentSaved(const AZ::Uuid& documentId) - { - bool isModified = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); - AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); - } - - void ShaderManagementConsoleWindow::CreateMenu() - { - Base::CreateMenu(); - - // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries - m_menuFile = menuBar()->addMenu("&File"); - - m_actionOpen = m_menuFile->addAction("&Open...", [this]() { - const AZStd::vector assetTypes = { - }; - - const AZStd::string filePath = AtomToolsFramework::GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); - if (!filePath.empty()) - { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, filePath); - } - }, QKeySequence::Open); - - m_actionOpenRecent = m_menuFile->addAction("Open &Recent"); - - m_menuFile->addSeparator(); - - m_actionSave = m_menuFile->addAction("&Save", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); - if (!result) - { - SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); - } - }, QKeySequence::Save); - - m_actionSaveAsCopy = m_menuFile->addAction("Save &As...", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - const QString documentPath = GetDocumentPath(documentId); - - bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy, - documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); - if (!result) - { - SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); - } - }, QKeySequence::SaveAs); - - m_actionSaveAll = m_menuFile->addAction("Save A&ll", [this]() { - bool result = false; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments); - if (!result) - { - SetStatusError(tr("Document save all failed")); - } - }); - - m_menuFile->addSeparator(); - - m_actionClose = m_menuFile->addAction("&Close", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); - }, QKeySequence::Close); - - m_actionCloseAll = m_menuFile->addAction("Close All", [this]() { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); - }); - - m_actionCloseOthers = m_menuFile->addAction("Close Others", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); - }); - - m_menuFile->addSeparator(); - - m_menuFile->addAction("Run &Python...", [this]() { - const QString script = QFileDialog::getOpenFileName(this, "Run Script", QString(), QString("*.py")); - if (!script.isEmpty()) - { - AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilename, script.toUtf8().constData()); - } - }); - - m_menuFile->addSeparator(); - - m_actionExit = m_menuFile->addAction("E&xit", [this]() { - close(); - }, QKeySequence::Quit); - - m_menuEdit = menuBar()->addMenu("&Edit"); - - m_actionUndo = m_menuEdit->addAction("&Undo", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - bool result = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Undo); - if (!result) - { - SetStatusError(tr("Document undo failed: %1").arg(GetDocumentPath(documentId))); - } - }, QKeySequence::Undo); - - m_actionRedo = m_menuEdit->addAction("&Redo", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); - bool result = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Redo); - if (!result) - { - SetStatusError(tr("Document redo failed: %1").arg(GetDocumentPath(documentId))); - } - }, QKeySequence::Redo); - - m_menuEdit->addSeparator(); - - m_actionSettings = m_menuEdit->addAction("&Settings...", [this]() { - }, QKeySequence::Preferences); - m_actionSettings->setEnabled(false); - - m_menuView = menuBar()->addMenu("&View"); - - m_actionAssetBrowser = m_menuView->addAction("&Asset Browser", [this]() { - const AZStd::string label = "Asset Browser"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_actionPythonTerminal = m_menuView->addAction("Python &Terminal", [this]() { - const AZStd::string label = "Python Terminal"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - - m_menuView->addSeparator(); - - m_actionPreviousTab = m_menuView->addAction("&Previous Tab", [this]() { - SelectPreviousTab(); - }, Qt::CTRL | Qt::SHIFT | Qt::Key_Tab); //QKeySequence::PreviousChild is mapped incorrectly in Qt - - m_actionNextTab = m_menuView->addAction("&Next Tab", [this]() { - SelectNextTab(); - }, Qt::CTRL | Qt::Key_Tab); //QKeySequence::NextChild works as expected but mirroring Previous - - m_menuHelp = menuBar()->addMenu("&Help"); - - m_actionHelp = m_menuHelp->addAction("&Help...", [this]() { - }); - - m_actionAbout = m_menuHelp->addAction("&About...", [this]() { - }); - } - - void ShaderManagementConsoleWindow::CreateTabBar() - { - Base::CreateTabBar(); - - // This signal will be triggered whenever a tab is added, removed, selected, clicked, dragged - // When the last tab is removed tabIndex will be -1 and the document ID will be null - // This should automatically clear the active document - connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int tabIndex) { - const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); - }); - - connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int tabIndex) { - const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); - }); - } - - QString ShaderManagementConsoleWindow::GetDocumentPath(const AZ::Uuid& documentId) const - { - AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Handler::GetAbsolutePath); - return absolutePath.c_str(); - } - - void ShaderManagementConsoleWindow::OpenTabContextMenu() - { - const QTabBar* tabBar = m_tabWidget->tabBar(); - const QPoint position = tabBar->mapFromGlobal(QCursor::pos()); - const int clickedTabIndex = tabBar->tabAt(position); - const int currentTabIndex = tabBar->currentIndex(); - if (clickedTabIndex >= 0) - { - QMenu tabMenu; - const QString selectActionName = (currentTabIndex == clickedTabIndex) ? "Select in Browser" : "Select"; - tabMenu.addAction(selectActionName, [this, clickedTabIndex]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); - }); - tabMenu.addAction("Close", [this, clickedTabIndex]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); - }); - auto closeOthersAction = tabMenu.addAction("Close Others", [this, clickedTabIndex]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); - }); - closeOthersAction->setEnabled(tabBar->count() > 1); - tabMenu.exec(QCursor::pos()); - } - } - - QStandardItemModel* ShaderManagementConsoleWindow::CreateDocumentContent(const AZ::Uuid& documentId) + QWidget* ShaderManagementConsoleWindow::CreateViewForDocumemt(const AZ::Uuid& documentId) { AZStd::unordered_set optionNames; size_t shaderOptionCount = 0; - ShaderManagementConsoleDocumentRequestBus::EventResult(shaderOptionCount, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionCount); + ShaderManagementConsoleDocumentRequestBus::EventResult( + shaderOptionCount, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionCount); for (size_t optionIndex = 0; optionIndex < shaderOptionCount; ++optionIndex) { AZ::RPI::ShaderOptionDescriptor shaderOptionDesc; - ShaderManagementConsoleDocumentRequestBus::EventResult(shaderOptionDesc, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionDescriptor, optionIndex); + ShaderManagementConsoleDocumentRequestBus::EventResult( + shaderOptionDesc, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionDescriptor, optionIndex); const char* optionName = shaderOptionDesc.GetName().GetCStr(); optionNames.insert(optionName); } size_t shaderVariantCount = 0; - ShaderManagementConsoleDocumentRequestBus::EventResult(shaderVariantCount, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantCount); + ShaderManagementConsoleDocumentRequestBus::EventResult( + shaderVariantCount, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantCount); auto model = new QStandardItemModel(); model->setRowCount(static_cast(shaderVariantCount)); @@ -425,7 +91,8 @@ namespace ShaderManagementConsole for (int variantIndex = 0; variantIndex < shaderVariantCount; ++variantIndex) { AZ::RPI::ShaderVariantListSourceData::VariantInfo shaderVariantInfo; - ShaderManagementConsoleDocumentRequestBus::EventResult(shaderVariantInfo, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantInfo, variantIndex); + ShaderManagementConsoleDocumentRequestBus::EventResult( + shaderVariantInfo, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantInfo, variantIndex); model->setHeaderData(variantIndex, Qt::Vertical, QString::number(variantIndex)); @@ -442,7 +109,11 @@ namespace ShaderManagementConsole } } - return model; + // The document tab contains a table view. + auto contentWidget = new QTableView(centralWidget()); + contentWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + contentWidget->setModel(model); + return contentWidget; } } // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h index 2b682f6c09..e21fe8551d 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h @@ -11,9 +11,7 @@ #if !defined(Q_MOC_RUN) #include #include -#include -#include -#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include @@ -30,64 +28,20 @@ namespace ShaderManagementConsole * its panels, managing selection of assets, and performing high-level actions like saving. It contains... */ class ShaderManagementConsoleWindow - : public AtomToolsFramework::AtomToolsMainWindow - , private AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler + : public AtomToolsFramework::AtomToolsDocumentMainWindow { Q_OBJECT public: AZ_CLASS_ALLOCATOR(ShaderManagementConsoleWindow, AZ::SystemAllocator, 0); - using Base = AtomToolsFramework::AtomToolsMainWindow; + using Base = AtomToolsFramework::AtomToolsDocumentMainWindow; ShaderManagementConsoleWindow(QWidget* parent = 0); ~ShaderManagementConsoleWindow(); - private: - // AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler overrides... - void OnDocumentOpened(const AZ::Uuid& documentId) override; - void OnDocumentClosed(const AZ::Uuid& documentId) override; - void OnDocumentModified(const AZ::Uuid& documentId) override; - void OnDocumentUndoStateChanged(const AZ::Uuid& documentId) override; - void OnDocumentSaved(const AZ::Uuid& documentId) override; - - void CreateMenu() override; - void CreateTabBar() override; - - QString GetDocumentPath(const AZ::Uuid& documentId) const; - - void OpenTabContextMenu() override; - - void closeEvent(QCloseEvent* closeEvent) override; - - QStandardItemModel* CreateDocumentContent(const AZ::Uuid& documentId); + protected: + QWidget* CreateViewForDocumemt(const AZ::Uuid& documentId) override; ShaderManagementConsoleToolBar* m_toolBar = nullptr; - - QMenu* m_menuFile = {}; - QMenu* m_menuNew = {}; - QAction* m_actionOpen = {}; - QAction* m_actionOpenRecent = {}; - QAction* m_actionClose = {}; - QAction* m_actionCloseAll = {}; - QAction* m_actionCloseOthers = {}; - QAction* m_actionSave = {}; - QAction* m_actionSaveAsCopy = {}; - QAction* m_actionSaveAll = {}; - QAction* m_actionExit = {}; - - QMenu* m_menuEdit = {}; - QAction* m_actionUndo = {}; - QAction* m_actionRedo = {}; - QAction* m_actionSettings = {}; - - QMenu* m_menuView = {}; - QAction* m_actionAssetBrowser = {}; - QAction* m_actionPythonTerminal = {}; - QAction* m_actionNextTab = {}; - QAction* m_actionPreviousTab = {}; - - QMenu* m_menuHelp = {}; - QAction* m_actionHelp = {}; - QAction* m_actionAbout = {}; }; } // namespace ShaderManagementConsole From 2c6e105d27400c1edffb51acb7e2605b740162f0 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 22 Aug 2021 23:53:20 -0500 Subject: [PATCH 22/26] restored view menu entries for dock widgets renamed document tab functions Signed-off-by: Guthrie Adams --- .../Document/AtomToolsDocumentMainWindow.h | 21 +++-- .../Window/AtomToolsMainWindow.h | 1 + .../Document/AtomToolsDocumentMainWindow.cpp | 90 +++++++++---------- .../Source/Window/AtomToolsMainWindow.cpp | 10 +++ .../Source/Window/MaterialEditorWindow.cpp | 21 +---- .../Code/Source/Window/MaterialEditorWindow.h | 20 ++--- .../Window/ShaderManagementConsoleWindow.cpp | 18 ++-- .../Window/ShaderManagementConsoleWindow.h | 10 +-- 8 files changed, 90 insertions(+), 101 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h index 883a8833ab..826d2427b1 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h @@ -37,26 +37,25 @@ namespace AtomToolsFramework QString GetDocumentPath(const AZ::Uuid& documentId) const; - AZ::Uuid GetDocumentIdFromTab(const int tabIndex) const; + AZ::Uuid GetDocumentTabId(const int tabIndex) const; - void AddTabForDocumentId( + void AddDocumentTab( const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip); - void RemoveTabForDocumentId(const AZ::Uuid& documentId); + void RemoveDocumentTab(const AZ::Uuid& documentId); - void UpdateTabForDocumentId( + void UpdateDocumentTab( const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified); - void SelectPreviousTab(); + void SelectPrevDocumentTab(); + void SelectNextDocumentTab(); - void SelectNextTab(); - - virtual void OpenTabContextMenu(); - virtual bool GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath); - virtual bool GetOpenFileInfo(AZStd::string& openPath); - virtual QWidget* CreateViewForDocumemt(const AZ::Uuid& documentId); + virtual QWidget* CreateDocumentTabView(const AZ::Uuid& documentId); + virtual void OpenDocumentTabContextMenu(); + virtual bool GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath); + virtual bool GetOpenDocumentParams(AZStd::string& openPath); // AtomToolsDocumentNotificationBus::Handler overrides... void OnDocumentOpened(const AZ::Uuid& documentId) override; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h index 8d30e42bbb..fab6e2fb01 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h @@ -54,5 +54,6 @@ namespace AtomToolsFramework QMenu* m_menuHelp = {}; AZStd::unordered_map m_dockWidgets; + AZStd::unordered_map m_dockActions; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp index 4e7bc8edbd..f78950c2e9 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp @@ -47,7 +47,7 @@ namespace AtomToolsFramework m_actionNew = CreateAction("&New...", [this]() { AZStd::string openPath; AZStd::string savePath; - if (GetCreateFileInfo(openPath, savePath)) + if (GetCreateDocumentParams(openPath, savePath)) { AtomToolsDocumentSystemRequestBus::Broadcast( &AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, openPath, savePath); @@ -57,7 +57,7 @@ namespace AtomToolsFramework m_actionOpen = CreateAction("&Open...", [this]() { AZStd::string openPath; - if (GetOpenFileInfo(openPath)) + if (GetOpenDocumentParams(openPath)) { AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openPath); } @@ -66,7 +66,7 @@ namespace AtomToolsFramework m_menuFile->insertSeparator(insertPostion); m_actionSave = CreateAction("&Save", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); bool result = false; AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); if (!result) @@ -77,7 +77,7 @@ namespace AtomToolsFramework m_menuFile->insertAction(insertPostion, m_actionSave); m_actionSaveAsCopy = CreateAction("Save &As...", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); const QString documentPath = GetDocumentPath(documentId); bool result = false; @@ -91,7 +91,7 @@ namespace AtomToolsFramework m_menuFile->insertAction(insertPostion, m_actionSaveAsCopy); m_actionSaveAsChild = CreateAction("Save As &Child...", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); const QString documentPath = GetDocumentPath(documentId); bool result = false; @@ -116,7 +116,7 @@ namespace AtomToolsFramework m_menuFile->insertSeparator(insertPostion); m_actionClose = CreateAction("&Close", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); }, QKeySequence::Close); m_menuFile->insertAction(insertPostion, m_actionClose); @@ -127,7 +127,7 @@ namespace AtomToolsFramework m_menuFile->insertAction(insertPostion, m_actionCloseAll); m_actionCloseOthers = CreateAction("Close Others", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); }); m_menuFile->insertAction(insertPostion, m_actionCloseOthers); @@ -136,7 +136,7 @@ namespace AtomToolsFramework insertPostion = !m_menuEdit->actions().empty() ? m_menuEdit->actions().front() : nullptr; m_actionUndo = CreateAction("&Undo", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); bool result = false; AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::Undo); if (!result) @@ -147,7 +147,7 @@ namespace AtomToolsFramework m_menuEdit->insertAction(insertPostion, m_actionUndo); m_actionRedo = CreateAction("&Redo", [this]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); bool result = false; AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::Redo); if (!result) @@ -164,12 +164,12 @@ namespace AtomToolsFramework "&Previous Tab", [this]() { - SelectPreviousTab(); + SelectPrevDocumentTab(); }, Qt::CTRL | Qt::SHIFT | Qt::Key_Tab); //QKeySequence::PreviousChild is mapped incorrectly in Qt m_menuView->insertAction(insertPostion, m_actionPreviousTab); m_actionNextTab = CreateAction("&Next Tab", [this]() { - SelectNextTab(); + SelectNextDocumentTab(); }, Qt::CTRL | Qt::Key_Tab); //QKeySequence::NextChild works as expected but mirroring Previous m_menuView->insertAction(insertPostion, m_actionNextTab); m_menuView->insertSeparator(insertPostion); @@ -193,19 +193,19 @@ namespace AtomToolsFramework // When the last tab is removed tabIndex will be -1 and the document ID will be null // This should automatically clear the active document connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int tabIndex) { - const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); + const AZ::Uuid documentId = GetDocumentTabId(tabIndex); AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); }); connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int tabIndex) { - const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); + const AZ::Uuid documentId = GetDocumentTabId(tabIndex); AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); }); // Add context menu for right-clicking on tabs m_tabWidget->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu); connect(m_tabWidget, &QWidget::customContextMenuRequested, this, [this]() { - OpenTabContextMenu(); + OpenDocumentTabContextMenu(); }); centralWidget()->layout()->addWidget(m_tabWidget); @@ -218,7 +218,7 @@ namespace AtomToolsFramework return absolutePath.c_str(); } - AZ::Uuid AtomToolsDocumentMainWindow::GetDocumentIdFromTab(const int tabIndex) const + AZ::Uuid AtomToolsDocumentMainWindow::GetDocumentTabId(const int tabIndex) const { const QVariant tabData = m_tabWidget->tabBar()->tabData(tabIndex); if (!tabData.isNull()) @@ -232,7 +232,7 @@ namespace AtomToolsFramework return AZ::Uuid::CreateNull(); } - void AtomToolsDocumentMainWindow::AddTabForDocumentId( + void AtomToolsDocumentMainWindow::AddDocumentTab( const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip) { // Blocking signals from the tab bar so the currentChanged signal is not sent while a document is already being opened. @@ -242,7 +242,7 @@ namespace AtomToolsFramework // If a tab for this document already exists then select it instead of creating a new one for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) { - if (documentId == GetDocumentIdFromTab(tabIndex)) + if (documentId == GetDocumentTabId(tabIndex)) { m_tabWidget->setCurrentIndex(tabIndex); m_tabWidget->repaint(); @@ -250,7 +250,7 @@ namespace AtomToolsFramework } } - const int tabIndex = m_tabWidget->addTab(CreateViewForDocumemt(documentId), label.c_str()); + const int tabIndex = m_tabWidget->addTab(CreateDocumentTabView(documentId), label.c_str()); // The user can manually reorder tabs which will invalidate any association by index. // We need to store the document ID with the tab using the tab instead of a separate mapping. @@ -261,13 +261,13 @@ namespace AtomToolsFramework m_tabWidget->repaint(); } - void AtomToolsDocumentMainWindow::RemoveTabForDocumentId(const AZ::Uuid& documentId) + void AtomToolsDocumentMainWindow::RemoveDocumentTab(const AZ::Uuid& documentId) { // We are not blocking signals here because we want closing tabs to close the associated document // and automatically select the next document. for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) { - if (documentId == GetDocumentIdFromTab(tabIndex)) + if (documentId == GetDocumentTabId(tabIndex)) { m_tabWidget->removeTab(tabIndex); m_tabWidget->setVisible(m_tabWidget->count() > 0); @@ -277,7 +277,7 @@ namespace AtomToolsFramework } } - void AtomToolsDocumentMainWindow::UpdateTabForDocumentId( + void AtomToolsDocumentMainWindow::UpdateDocumentTab( const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified) { // Whenever a document is opened, saved, or modified we need to update the tab label @@ -288,7 +288,7 @@ namespace AtomToolsFramework // We must iterate over all of the tabs to find the one associated with this document. for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) { - if (documentId == GetDocumentIdFromTab(tabIndex)) + if (documentId == GetDocumentTabId(tabIndex)) { // We use an asterisk prepended to the file name to denote modified document // Appending is standard and preferred but the tabs elide from the @@ -303,7 +303,7 @@ namespace AtomToolsFramework } } - void AtomToolsDocumentMainWindow::SelectPreviousTab() + void AtomToolsDocumentMainWindow::SelectPrevDocumentTab() { if (m_tabWidget->count() > 1) { @@ -312,7 +312,7 @@ namespace AtomToolsFramework } } - void AtomToolsDocumentMainWindow::SelectNextTab() + void AtomToolsDocumentMainWindow::SelectNextDocumentTab() { if (m_tabWidget->count() > 1) { @@ -320,7 +320,16 @@ namespace AtomToolsFramework } } - void AtomToolsDocumentMainWindow::OpenTabContextMenu() + inline QWidget* AtomToolsDocumentMainWindow::CreateDocumentTabView(const AZ::Uuid& documentId) + { + AZ_UNUSED(documentId); + auto contentWidget = new QWidget(centralWidget()); + contentWidget->setContentsMargins(0, 0, 0, 0); + contentWidget->setFixedSize(0, 0); + return contentWidget; + } + + void AtomToolsDocumentMainWindow::OpenDocumentTabContextMenu() { const QTabBar* tabBar = m_tabWidget->tabBar(); const QPoint position = tabBar->mapFromGlobal(QCursor::pos()); @@ -331,15 +340,15 @@ namespace AtomToolsFramework QMenu tabMenu; const QString selectActionName = (currentTabIndex == clickedTabIndex) ? "Select in Browser" : "Select"; tabMenu.addAction(selectActionName, [this, clickedTabIndex]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); + const AZ::Uuid documentId = GetDocumentTabId(clickedTabIndex); AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); }); tabMenu.addAction("Close", [this, clickedTabIndex]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); + const AZ::Uuid documentId = GetDocumentTabId(clickedTabIndex); AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); }); auto closeOthersAction = tabMenu.addAction("Close Others", [this, clickedTabIndex]() { - const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); + const AZ::Uuid documentId = GetDocumentTabId(clickedTabIndex); AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); }); closeOthersAction->setEnabled(tabBar->count() > 1); @@ -347,28 +356,19 @@ namespace AtomToolsFramework } } - inline bool AtomToolsDocumentMainWindow::GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) + inline bool AtomToolsDocumentMainWindow::GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath) { AZ_UNUSED(openPath); AZ_UNUSED(savePath); return false; } - inline bool AtomToolsDocumentMainWindow::GetOpenFileInfo(AZStd::string& openPath) + inline bool AtomToolsDocumentMainWindow::GetOpenDocumentParams(AZStd::string& openPath) { AZ_UNUSED(openPath); return false; } - inline QWidget* AtomToolsDocumentMainWindow::CreateViewForDocumemt(const AZ::Uuid& documentId) - { - AZ_UNUSED(documentId); - auto contentWidget = new QWidget(centralWidget()); - contentWidget->setContentsMargins(0, 0, 0, 0); - contentWidget->setFixedSize(0, 0); - return contentWidget; - } - void AtomToolsDocumentMainWindow::OnDocumentOpened(const AZ::Uuid& documentId) { bool isOpen = false; @@ -390,8 +390,8 @@ namespace AtomToolsFramework if (!documentId.IsNull() && isOpen) { // Create a new tab for the document ID and assign it's label to the file name of the document. - AddTabForDocumentId(documentId, filename, absolutePath); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + AddDocumentTab(documentId, filename, absolutePath); + UpdateDocumentTab(documentId, filename, absolutePath, isModified); } const bool hasTabs = m_tabWidget->count() > 0; @@ -426,7 +426,7 @@ namespace AtomToolsFramework void AtomToolsDocumentMainWindow::OnDocumentClosed(const AZ::Uuid& documentId) { - RemoveTabForDocumentId(documentId); + RemoveDocumentTab(documentId); SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); } @@ -438,12 +438,12 @@ namespace AtomToolsFramework AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); AZStd::string filename; AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + UpdateDocumentTab(documentId, filename, absolutePath, isModified); } void AtomToolsDocumentMainWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) { - if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex())) + if (documentId == GetDocumentTabId(m_tabWidget->currentIndex())) { bool canUndo = false; AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); @@ -462,7 +462,7 @@ namespace AtomToolsFramework AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); AZStd::string filename; AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + UpdateDocumentTab(documentId, filename, absolutePath, isModified); SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp index e586dbc588..aeca51230a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp @@ -72,6 +72,10 @@ namespace AtomToolsFramework addDockWidget(aznumeric_cast(area), dockWidget); resizeDocks({ dockWidget }, { 400 }, aznumeric_cast(orientation)); m_dockWidgets[name] = dockWidget; + + m_dockActions[name] = m_menuView->addAction(name.c_str(), [this, name](){ + SetDockWidgetVisible(name, !IsDockWidgetVisible(name)); + }); return true; } @@ -83,6 +87,12 @@ namespace AtomToolsFramework delete dockWidgetItr->second; m_dockWidgets.erase(dockWidgetItr); } + auto dockActionItr = m_dockActions.find(name); + if (dockActionItr != m_dockActions.end()) + { + delete dockActionItr->second; + m_dockActions.erase(dockActionItr); + } } void AtomToolsMainWindow::SetDockWidgetVisible(const AZStd::string& name, bool visible) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp index 5f895ba804..0be6925701 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp @@ -98,10 +98,6 @@ namespace MaterialEditor OnDocumentOpened(AZ::Uuid::CreateNull()); } - MaterialEditorWindow::~MaterialEditorWindow() - { - } - void MaterialEditorWindow::ResizeViewportRenderTarget(uint32_t width, uint32_t height) { QSize requestedViewportSize = QSize(width, height) / devicePixelRatioF(); @@ -133,7 +129,7 @@ namespace MaterialEditor m_materialViewport->UnlockRenderTargetSize(); } - bool MaterialEditorWindow::GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) + bool MaterialEditorWindow::GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath) { CreateMaterialDialog createDialog(this); createDialog.adjustSize(); @@ -149,22 +145,13 @@ namespace MaterialEditor return false; } - bool MaterialEditorWindow::GetOpenFileInfo(AZStd::string& openPath) + bool MaterialEditorWindow::GetOpenDocumentParams(AZStd::string& openPath) { const AZStd::vector assetTypes = { azrtti_typeid() }; openPath = AtomToolsFramework::GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); return !openPath.empty(); } - QWidget* MaterialEditorWindow::CreateViewForDocumemt(const AZ::Uuid& documentId) - { - AZ_UNUSED(documentId); - auto contentWidget = new QWidget(centralWidget()); - contentWidget->setContentsMargins(0, 0, 0, 0); - contentWidget->setFixedSize(0, 0); - return contentWidget; - } - void MaterialEditorWindow::OpenSettings() { SettingsDialog dialog(this); @@ -177,10 +164,6 @@ namespace MaterialEditor dialog.exec(); } - void MaterialEditorWindow::OpenAbout() - { - } - void MaterialEditorWindow::closeEvent(QCloseEvent* closeEvent) { // Capture docking state before shutdown diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h index 72fd525fce..bed2aa34e4 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h @@ -19,13 +19,11 @@ AZ_POP_DISABLE_WARNING namespace MaterialEditor { - /** - * MaterialEditorWindow is the main class. Its responsibility is limited to initializing and connecting - * its panels, managing selection of assets, and performing high-level actions like saving. It contains... - * 1) MaterialBrowser - The user browses for Material (.material) assets. - * 2) MaterialViewport - The user can see the selected Material applied to a model. - * 3) MaterialPropertyInspector - The user edits the properties of the selected Material. - */ + //! MaterialEditorWindow is the main class. Its responsibility is limited to initializing and connecting + //! its panels, managing selection of assets, and performing high-level actions like saving. It contains... + //! 1) MaterialBrowser - The user browses for Material (.material) assets. + //! 2) MaterialViewport - The user can see the selected Material applied to a model. + //! 3) MaterialPropertyInspector - The user edits the properties of the selected Material. class MaterialEditorWindow : public AtomToolsFramework::AtomToolsDocumentMainWindow { @@ -36,19 +34,17 @@ namespace MaterialEditor using Base = AtomToolsFramework::AtomToolsDocumentMainWindow; MaterialEditorWindow(QWidget* parent = 0); - ~MaterialEditorWindow(); + ~MaterialEditorWindow() = default; protected: void ResizeViewportRenderTarget(uint32_t width, uint32_t height) override; void LockViewportRenderTargetSize(uint32_t width, uint32_t height) override; void UnlockViewportRenderTargetSize() override; - bool GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) override; - bool GetOpenFileInfo(AZStd::string& openPath) override; - QWidget* CreateViewForDocumemt(const AZ::Uuid& documentId) override; + bool GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath) override; + 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/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp index e44101c300..29dafe99fe 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp @@ -5,12 +5,12 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ - + +#include +#include #include #include #include -#include -#include #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT @@ -49,14 +49,16 @@ namespace ShaderManagementConsole // Restore geometry and show the window mainWindowWrapper->showFromSettings(); + // Disable unused actions + m_actionNew->setVisible(false); + m_actionNew->setEnabled(false); + m_actionSaveAsChild->setVisible(false); + m_actionSaveAsChild->setEnabled(false); + OnDocumentOpened(AZ::Uuid::CreateNull()); } - ShaderManagementConsoleWindow::~ShaderManagementConsoleWindow() - { - } - - QWidget* ShaderManagementConsoleWindow::CreateViewForDocumemt(const AZ::Uuid& documentId) + QWidget* ShaderManagementConsoleWindow::CreateDocumentTabView(const AZ::Uuid& documentId) { AZStd::unordered_set optionNames; diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h index e21fe8551d..3ba122674a 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h @@ -23,10 +23,8 @@ AZ_POP_DISABLE_WARNING namespace ShaderManagementConsole { - /** - * ShaderManagementConsoleWindow is the main class. Its responsibility is limited to initializing and connecting - * its panels, managing selection of assets, and performing high-level actions like saving. It contains... - */ + //! ShaderManagementConsoleWindow is the main class. Its responsibility is limited to initializing and connecting + //! its panels, managing selection of assets, and performing high-level actions like saving. It contains... class ShaderManagementConsoleWindow : public AtomToolsFramework::AtomToolsDocumentMainWindow { @@ -37,10 +35,10 @@ namespace ShaderManagementConsole using Base = AtomToolsFramework::AtomToolsDocumentMainWindow; ShaderManagementConsoleWindow(QWidget* parent = 0); - ~ShaderManagementConsoleWindow(); + ~ShaderManagementConsoleWindow() = default; protected: - QWidget* CreateViewForDocumemt(const AZ::Uuid& documentId) override; + QWidget* CreateDocumentTabView(const AZ::Uuid& documentId) override; ShaderManagementConsoleToolBar* m_toolBar = nullptr; }; From 3d2d2dd60fda3f5f1b7454c2718fe3f07b014eff Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 23 Aug 2021 10:40:44 -0500 Subject: [PATCH 23/26] fixing linux non unity build Signed-off-by: Guthrie Adams --- .../Code/Source/Document/AtomToolsDocumentMainWindow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp index f78950c2e9..c39bfc8327 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp @@ -320,7 +320,7 @@ namespace AtomToolsFramework } } - inline QWidget* AtomToolsDocumentMainWindow::CreateDocumentTabView(const AZ::Uuid& documentId) + QWidget* AtomToolsDocumentMainWindow::CreateDocumentTabView(const AZ::Uuid& documentId) { AZ_UNUSED(documentId); auto contentWidget = new QWidget(centralWidget()); @@ -356,14 +356,14 @@ namespace AtomToolsFramework } } - inline bool AtomToolsDocumentMainWindow::GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath) + bool AtomToolsDocumentMainWindow::GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath) { AZ_UNUSED(openPath); AZ_UNUSED(savePath); return false; } - inline bool AtomToolsDocumentMainWindow::GetOpenDocumentParams(AZStd::string& openPath) + bool AtomToolsDocumentMainWindow::GetOpenDocumentParams(AZStd::string& openPath) { AZ_UNUSED(openPath); return false; From dfc5baae34dbbdc417d743a3c9e785aab95fb76b Mon Sep 17 00:00:00 2001 From: Kyle B Date: Mon, 23 Aug 2021 12:46:00 -0700 Subject: [PATCH 24/26] fixed casting errors Signed-off-by: Kyle B --- .../CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index b1bfb30285..ade4beaa33 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -109,7 +109,7 @@ namespace AZ } values.reserve(lodCount + 1); - values.push_back({0, "Default (Highest)" }); + values.push_back({ aznumeric_cast(0), "Default (Highest)" }); for (uint32_t i = 1; i < lodCount; ++i) { From ef9666cb105e4088efd426680313153aad15c344 Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Tue, 24 Aug 2021 13:43:19 +0100 Subject: [PATCH 25/26] fixed case where the Physics Asset could not be set correctly (#3390) Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com> --- Gems/PhysX/Code/Source/EditorColliderComponent.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 2445aba9bd..c337ab0a85 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -122,7 +122,10 @@ namespace PhysX if (m_shapeType != Physics::ShapeType::PhysicsAsset && m_lastShapeType == Physics::ShapeType::PhysicsAsset) { + //clean up any reference to a physics assets, and re-initialize to an empty Pipeline::MeshAsset asset. m_physicsAsset.m_pxAsset.Reset(); + m_physicsAsset.m_pxAsset = AZ::Data::Asset(AZ::Data::AssetLoadBehavior::QueueLoad); + m_physicsAsset.m_configuration = Physics::PhysicsAssetShapeConfiguration(); } m_lastShapeType = m_shapeType; From 8c573979a96c4dd12705668007e3268102f0ae04 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Tue, 24 Aug 2021 16:25:08 +0100 Subject: [PATCH 26/26] Updates to camera tests to support different delta times and some further tidy-up (#3324) * updates to camera tests to support different delta times and some further tidy-up Signed-off-by: hultonha * support variable delta time in mouse move test Signed-off-by: hultonha --- .../test_ModularViewportCameraController.cpp | 298 ++++++++++++------ .../AzFramework/Viewport/CameraInput.cpp | 1 - .../Viewport/ViewportMessages.h | 4 +- .../Viewport/RenderViewportWidget.h | 1 - .../Source/Viewport/RenderViewportWidget.cpp | 5 - 5 files changed, 198 insertions(+), 111 deletions(-) diff --git a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp index 6fcf3faffd..28bc6fe3b3 100644 --- a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp +++ b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp @@ -19,6 +19,66 @@ namespace UnitTest using AzToolsFramework::ViewportInteraction::MouseInteractionEvent; + class ViewportMouseCursorRequestImpl : public AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler + { + public: + void Connect(const AzFramework::ViewportId viewportId, AzToolsFramework::QtEventToAzInputMapper* inputChannelMapper) + { + AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusConnect(viewportId); + m_inputChannelMapper = inputChannelMapper; + } + + void Disconnect() + { + AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusDisconnect(); + } + + // ViewportMouseCursorRequestBus overrides ... + void BeginCursorCapture() override; + void EndCursorCapture() override; + bool IsMouseOver() const override; + + private: + AzToolsFramework::QtEventToAzInputMapper* m_inputChannelMapper = nullptr; + }; + + void ViewportMouseCursorRequestImpl::BeginCursorCapture() + { + m_inputChannelMapper->SetCursorCaptureEnabled(true); + } + + void ViewportMouseCursorRequestImpl::EndCursorCapture() + { + m_inputChannelMapper->SetCursorCaptureEnabled(false); + } + + bool ViewportMouseCursorRequestImpl::IsMouseOver() const + { + return true; + } + + class TestModularCameraViewportContextImpl : public AtomToolsFramework::ModularCameraViewportContext + { + public: + AZ::Transform GetCameraTransform() const override + { + return m_cameraTransform; + } + + void SetCameraTransform(const AZ::Transform& transform) override + { + m_cameraTransform = transform; + } + + void ConnectViewMatrixChangedHandler(AZ::RPI::ViewportContext::MatrixChangedEvent::Handler&) override + { + // noop + } + + private: + AZ::Transform m_cameraTransform = AZ::Transform::CreateIdentity(); + }; + class ModularViewportCameraControllerFixture : public AllocatorsTestFixture { public: @@ -48,123 +108,159 @@ namespace UnitTest AllocatorsTestFixture::TearDown(); } + void PrepareCollaborators() + { + AzFramework::NativeWindowHandle nativeWindowHandle = nullptr; + + // listen for events signaled from QtEventToAzInputMapper and forward to the controller list + QObject::connect( + m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(), + [this, nativeWindowHandle](const AzFramework::InputChannel* inputChannel, [[maybe_unused]] QEvent* event) + { + m_controllerList->HandleInputChannelEvent( + AzFramework::ViewportControllerInputEvent{ TestViewportId, nativeWindowHandle, *inputChannel }); + }); + + m_mockWindowRequests.Connect(nativeWindowHandle); + + using ::testing::Return; + // note: WindowRequests is used internally by ModularViewportCameraController, this ensures it returns the viewport size we want + ON_CALL(m_mockWindowRequests, GetClientAreaSize()) + .WillByDefault(Return(AzFramework::WindowSize(WidgetSize.width(), WidgetSize.height()))); + + // respond to begin/end cursor capture events + m_viewportMouseCursorRequests.Connect(TestViewportId, m_inputChannelMapper.get()); + + // create editor modular camera + auto controller = CreateModularViewportCameraController(TestViewportId); + + // set some overrides for the test + controller->SetCameraViewportContextBuilderCallback( + [this](AZStd::unique_ptr& cameraViewportContext) + { + cameraViewportContext = AZStd::make_unique(); + m_cameraViewportContextView = cameraViewportContext.get(); + }); + + // disable smoothing in the test + controller->SetCameraPropsBuilderCallback( + [](AzFramework::CameraProps& cameraProps) + { + cameraProps.m_rotateSmoothingEnabledFn = [] + { + return false; + }; + + cameraProps.m_translateSmoothingEnabledFn = [] + { + return false; + }; + }); + + m_controllerList->Add(controller); + } + + void HaltCollaborators() + { + m_mockWindowRequests.Disconnect(); + m_viewportMouseCursorRequests.Disconnect(); + m_cameraViewportContextView = nullptr; + } + + void RepeatDiagonalMouseMovements(const AZStd::function& deltaTimeFn) + { + // move to the center of the screen + auto start = QPoint(WidgetSize.width() / 2, WidgetSize.height() / 2); + MouseMove(m_rootWidget.get(), start, QPoint(0, 0)); + m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTimeFn()), AZ::ScriptTimePoint() }); + + // move mouse diagonally to top right, then to bottom left and back repeatedly + auto current = start; + auto halfDelta = QPoint(200, -200); + const int iterationsPerDiagonal = 50; + for (int diagonals = 0; diagonals < 80; ++diagonals) + { + for (int i = 0; i < iterationsPerDiagonal; ++i) + { + MousePressAndMove(m_rootWidget.get(), current, halfDelta / iterationsPerDiagonal, Qt::MouseButton::RightButton); + m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTimeFn()), AZ::ScriptTimePoint() }); + current += halfDelta / iterationsPerDiagonal; + } + + if (diagonals % 2 == 0) + { + halfDelta.setX(halfDelta.x() * -1); + halfDelta.setY(halfDelta.y() * -1); + } + } + + QTest::mouseRelease(m_rootWidget.get(), Qt::MouseButton::RightButton, Qt::KeyboardModifier::NoModifier, current); + m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTimeFn()), AZ::ScriptTimePoint() }); + } + AZStd::unique_ptr m_rootWidget; AzFramework::ViewportControllerListPtr m_controllerList; AZStd::unique_ptr m_inputChannelMapper; + ::testing::NiceMock m_mockWindowRequests; + ViewportMouseCursorRequestImpl m_viewportMouseCursorRequests; + AtomToolsFramework::ModularCameraViewportContext* m_cameraViewportContextView = nullptr; }; const AzFramework::ViewportId ModularViewportCameraControllerFixture::TestViewportId = AzFramework::ViewportId(0); - class TestModularCameraViewportContextImpl : public AtomToolsFramework::ModularCameraViewportContext + TEST_F(ModularViewportCameraControllerFixture, MouseMovementDoesNotAccumulateExcessiveDriftInModularViewportCameraWithVaryingDeltaTime) { - public: - AZ::Transform GetCameraTransform() const override - { - return m_cameraTransform; - } - - void SetCameraTransform(const AZ::Transform& transform) override - { - m_cameraTransform = transform; - } - - void ConnectViewMatrixChangedHandler(AZ::RPI::ViewportContext::MatrixChangedEvent::Handler&) override - { - // noop - } - - private: - AZ::Transform m_cameraTransform = AZ::Transform::CreateIdentity(); - }; - - TEST_F(ModularViewportCameraControllerFixture, Mouse_movement_does_not_accumulate_excessive_drift_in_modular_viewport_camera) - { - AzFramework::NativeWindowHandle nativeWindowHandle = nullptr; - - const float deltaTime = 1.0f / 60.0f; // mimic 60fps - // Given - // listen for events signaled from QtEventToAzInputMapper and forward to the controller list - QObject::connect( - m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(), - [this, nativeWindowHandle](const AzFramework::InputChannel* inputChannel, [[maybe_unused]] QEvent* event) - { - m_controllerList->HandleInputChannelEvent( - AzFramework::ViewportControllerInputEvent{ TestViewportId, nativeWindowHandle, *inputChannel }); - }); - - using ::testing::NiceMock; - using ::testing::Return; - - NiceMock mockWindowRequests; - mockWindowRequests.Connect(nativeWindowHandle); - - // note: WindowRequests is used internally by ModularViewportCameraController, this ensures it returns the viewport size we want - ON_CALL(mockWindowRequests, GetClientAreaSize()) - .WillByDefault(Return(AzFramework::WindowSize(WidgetSize.width(), WidgetSize.height()))); - - // create editor modular camera - auto controller = CreateModularViewportCameraController(TestViewportId); - - // set some overrides for the test - AtomToolsFramework::ModularCameraViewportContext* cameraViewportContextView = nullptr; - controller->SetCameraViewportContextBuilderCallback( - [&cameraViewportContextView](AZStd::unique_ptr& cameraViewportContext) - { - cameraViewportContext = AZStd::make_unique(); - cameraViewportContextView = cameraViewportContext.get(); - }); - - controller->SetCameraPropsBuilderCallback( - [](AzFramework::CameraProps& cameraProps) - { - cameraProps.m_rotateSmoothingEnabledFn = [] - { - return false; - }; - - cameraProps.m_translateSmoothingEnabledFn = [] - { - return false; - }; - }); - - m_controllerList->Add(controller); - - // move to the center of the screen - auto start = QPoint(WidgetSize.width() / 2, WidgetSize.height() / 2); - MouseMove(m_rootWidget.get(), start, QPoint(0, 0)); - m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() }); + PrepareCollaborators(); // When - // move mouse diagonally to top right, then to bottom left and back repeatedly - auto current = start; - auto halfDelta = QPoint(200, -200); - const int iterationsPerDiagonal = 50; - for (int diagonals = 0; diagonals < 80; ++diagonals) - { - for (int i = 0; i < iterationsPerDiagonal; ++i) + RepeatDiagonalMouseMovements( + [t = 0.0f]() mutable { - MousePressAndMove(m_rootWidget.get(), current, halfDelta / iterationsPerDiagonal, Qt::MouseButton::RightButton); - m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() }); - current += halfDelta / iterationsPerDiagonal; - } - - if (diagonals % 2 == 0) - { - halfDelta.setX(halfDelta.x() * -1); - halfDelta.setY(halfDelta.y() * -1); - } - } - - QTest::mouseRelease(m_rootWidget.get(), Qt::MouseButton::RightButton, Qt::KeyboardModifier::NoModifier, current); - m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() }); + // vary between 30 and 50 fps (40 +/- 10) + const float fps = 40.0f + (10.0f * AZStd::sin(t)); + t += AZ::DegToRad(5.0f); + return 1.0f / fps; + }); // Then // ensure the camera rotation is the identity (no significant drift has occurred as we moved the mouse) - const AZ::Transform cameraRotation = cameraViewportContextView->GetCameraTransform(); + const AZ::Transform cameraRotation = m_cameraViewportContextView->GetCameraTransform(); EXPECT_THAT(cameraRotation.GetRotation(), IsClose(AZ::Quaternion::CreateIdentity())); - mockWindowRequests.Disconnect(); + // Clean-up + HaltCollaborators(); } + + class ModularViewportCameraControllerDeltaTimeParamFixture + : public ModularViewportCameraControllerFixture + , public ::testing::WithParamInterface // delta time + { + }; + + TEST_P( + ModularViewportCameraControllerDeltaTimeParamFixture, + MouseMovementDoesNotAccumulateExcessiveDriftInModularViewportCameraWithFixedDeltaTime) + { + // Given + PrepareCollaborators(); + + // When + RepeatDiagonalMouseMovements( + [this] + { + return GetParam(); + }); + + // Then + // ensure the camera rotation is the identity (no significant drift has occurred as we moved the mouse) + const AZ::Transform cameraRotation = m_cameraViewportContextView->GetCameraTransform(); + EXPECT_THAT(cameraRotation.GetRotation(), IsClose(AZ::Quaternion::CreateIdentity())); + + // Clean-up + HaltCollaborators(); + } + + INSTANTIATE_TEST_CASE_P( + All, ModularViewportCameraControllerDeltaTimeParamFixture, testing::Values(1.0f / 60.0f, 1.0f / 50.0f, 1.0f / 30.0f)); } // namespace UnitTest diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index 74adcd9543..72984f8111 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -802,7 +802,6 @@ namespace AzFramework { return VerticalMotionEvent{ aznumeric_cast(inputChannel.GetValue()) }; } - else if (inputChannelId == InputDeviceMouse::Movement::Z) { return ScrollEvent{ inputChannel.GetValue() }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h index 543d5fb3a5..f6ba87a0ec 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h @@ -275,9 +275,7 @@ namespace AzToolsFramework virtual void BeginCursorCapture() = 0; //! Restores the cursor and ends locking it in place, allowing it to be moved freely. virtual void EndCursorCapture() = 0; - //! Gets the most recent recorded cursor position in the viewport in screen space coordinates. - virtual AzFramework::ScreenPoint ViewportCursorScreenPosition() = 0; - //! Is mouse over viewport. + //! Is the mouse over the viewport. virtual bool IsMouseOver() const = 0; protected: diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h index bb26e116af..b6db6b78ae 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -109,7 +109,6 @@ namespace AtomToolsFramework // AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler ... void BeginCursorCapture() override; void EndCursorCapture() override; - AzFramework::ScreenPoint ViewportCursorScreenPosition() override; bool IsMouseOver() const override; // AzFramework::WindowRequestBus::Handler ... diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index bf356d2b99..cbb30ba6da 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -403,11 +403,6 @@ namespace AtomToolsFramework return aznumeric_cast(devicePixelRatioF()); } - AzFramework::ScreenPoint RenderViewportWidget::ViewportCursorScreenPosition() - { - return AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(m_mousePosition.toPoint()); - } - bool RenderViewportWidget::IsMouseOver() const { return m_mouseOver;